Uva 1391 (LA 3713) Astronauts (2-SAT问题)

今天学了2-SAT问题,就找了这道例题,敲了一下,还好过了。

2-SAT问题应该是把一些布尔变量之间的逻辑关系反映到一个无向图(有时可能是有向图)上来。通过推导的形式在这个有向图里面补边。再通过确定一些变量的值,使所有的变量都能符合题意中逻辑关系。补边方式 即如果Xi = true && Xj = false 不符合题意,那么如果Xi == true ,那么就在 Xi = true 和 Xj = true之间连一条边, 使得当Xi = true 时能马上确定 Xj = true。 在实际操作上总把一个点 Xi 拆成两个点 Xi*2 和 Xi*2+1, 其中 Xi*2 表示当 Xi 为假时, Xi*2+1 表示 当 Xi*2+1 为真时。 同时为了实现判别 Xi 的真假性的确定,以及 Xi 的值是否已确定。 用一个布尔数组mark来判断。若 mark[Xi*2] == 1 则 Xi 的值为假,mark[Xi*2+1] == 1 则 Xi 的值为真。 若 mark[Xi*2] == 1 && mark[Xi*2+1] == 1 则说明之前确定的变量是错误的。 若mark[Xi*2] == 0 && mark[Xi*2+1] == 0, 则需开始确定变量的值。确定变量的值时先假定其为假,若失败,再假定其为真。若再失败,则退出。成功则寻找下一个没确定的变量。当然,在失败之后,是需要把这期间的mark消除的。

此题代码如下

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<vector>
  5 #define maxn 100009
  6 #define rep(i,j,k) for(int i = j; i <= k; i++)
  7 using namespace std;
  8
  9 int n, m, a[maxn] = {0}, s[maxn][2] = {0};
 10 double po;
 11
 12 int read()
 13 {
 14     int s = 0, t = 1; char c = getchar();
 15     while( !isdigit(c) ){
 16         if( c == ‘-‘ ) t = -1; c = getchar();
 17     }
 18     while( isdigit(c) ){
 19         s = s * 10 + c - ‘0‘; c = getchar();
 20     }
 21     return s * t;
 22 }
 23
 24 struct TWO_SAT{
 25 int n;
 26 vector<int> q[maxn*2];
 27 int s[maxn*2], c;
 28 bool mark[maxn*2];
 29
 30 void init(int n){
 31     this-> n = n;
 32     rep(i,0,n*2-1) q[i].clear();
 33     memset(mark,0,sizeof(mark));
 34 }
 35
 36 bool dfs(int x)
 37 {
 38     if( mark[x^1] ) return false;
 39     if( mark[x] ) return true;
 40     s[c++] = x;
 41     mark[x] = 1;
 42     int s = q[x].size();
 43     rep(i,0,s-1){
 44         if( !dfs(q[x][i] )) return false;
 45     }
 46     return true;
 47 }
 48
 49 bool solve()
 50 {
 51     for(int i = 0; i < n*2; i += 2)
 52     {
 53         if( !mark[i] && !mark[i^1] ){
 54             c = 0;
 55             if( !dfs(i) ){
 56                 while( c > 0 ) mark[s[--c]] = 0;
 57                 if( !dfs(i+1) ) return false;
 58             }
 59         }
 60     }
 61     return true;
 62 }
 63 };
 64
 65 TWO_SAT solver;
 66
 67 bool test()
 68 {
 69     solver.init(n);
 70     rep(i,0,m-1){
 71         if( (a[s[i][0]] < po && a[s[i][1]] < po) || (a[s[i][0]] >= po && a[s[i][1]] >= po ) )
 72         {
 73                  solver.q[s[i][0]*2].push_back(s[i][1]*2+1);solver.q[s[i][0]*2+1].push_back(s[i][1]*2);
 74                  solver.q[s[i][1]*2].push_back(s[i][0]*2+1);solver.q[s[i][1]*2+1].push_back(s[i][0]*2);
 75
 76         }
 77         else {
 78             solver.q[s[i][0]*2+1].push_back(s[i][1]*2);
 79             solver.q[s[i][1]*2+1].push_back(s[i][0]*2);
 80         }
 81     }
 82
 83     bool ok = solver.solve();
 84     if( ok ){
 85         rep(i,0,n-1){
 86             if( a[i] < po ){
 87                 if( solver.mark[i*2] ) printf("B\n");
 88                 else printf("C\n");
 89             }
 90             else {
 91                 if( solver.mark[i*2] ) printf("A\n");
 92                 else printf("C\n");
 93             }
 94         }
 95     }
 96     return ok;
 97 }
 98
 99 int main()
100 {
101     while( scanf("%d%d", &n,&m) == 2 && n && m ){
102     int sum = 0;
103     rep(i,0,n-1) {
104         a[i] = read();
105         sum += a[i];
106     }
107     po = 1.0 * sum / n;
108     rep(i,0,m-1){
109         rep(j,0,1)
110         s[i][j] = read(), s[i][j]--;
111     }
112     if( !test() ) {
113         cout<<"No solution\n";
114     }
115     }
116     return 0;
117 }
时间: 2024-08-28 12:54:42

Uva 1391 (LA 3713) Astronauts (2-SAT问题)的相关文章

LA 3713 Astronauts

给个题目链接: https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1714 显然每个人只有两种选择:C或者A/B.而且后一种只和这个人的年龄有关. 这就是一个很显然的2-SAT模型了,显然有矛盾的不能都选C,如果两个人的年龄段还一样,那就更悲剧了,也不能同时选A/B. #include<iostream> #incl

UVA 1391 - Astronauts(2-SET)

UVA 1391 - Astronauts 题目链接 题意:给定一些宇航员,年龄小于平均数能做A和C,大于等于能做B和C,现在知道一些宇航员互相憎恨,不能让他们做同一个任务,问一直种安排方法满足条件 思路:2set问题,如果两种宇航员类型相同,就两个宇航员做不一样,加一条真或真,和假或假的边,如果类型不同,就加一条真或真的边 代码: #include <cstdio> #include <cstring> #include <cstdlib> #include <

UVa 1391 Astronauts (2SAT)

题意:给出一些宇航员他们的年龄,x是他们的平均年龄,其中A任务只能给年龄大于等于x的人,B任务只能给小于x的人,C任务没有限制.再给出m对人,他们不能同任务.现在要你输出一组符合要求的任务安排. 思路:2SAT. 设Ai表示第i个人的任务,如果i的年龄大于等于x,那么Ai=true表示分到A任务,flase表示分到C任务.如果i年龄小于x则Ai=true表示分到B任务,flase表示分到C任务. 考虑对于这m对里的每对人,如果他们是同组的,那么(Ai并非Aj)或(非Ai并Aj)等价于 (非Ai或

LA 3713

The Bandulu Space Agency (BSA) has plans for the following three space missions: Mission A: Landing on Ganymede, the largest moon of Jupiter. Mission B: Landing on Callisto, the second largest moon of Jupiter. Mission C: Landing on Titan, the largest

uva 1391 Astronauts(2-SAT)

/*翻译好题意 n个变量 不超过m*2句话*/ #include<iostream> #include<cstdio> #include<cstring> #include<vector> #define maxn 200010 using namespace std; int n,m,f[maxn],c,s[maxn],age[maxn],sum,a,b; vector<int>G[maxn]; bool Judge(int a,int b)

UVA Live 3713 Astronauts

用布尔变量表示状态,把限制条件转化为XνY的形式以后跑2SAT,根据变量取值输出方案. #include<bits/stdc++.h> using namespace std; const int maxn = 1e5+5; #define PB push_back bool vis[maxn*2]; vector<int> G[maxn*2]; int N,S[maxn*2],top; void initGraph(int n) { N = n*2; for(int i = 0;

UVa 1362(LA 3516) Exploring Pyramids

依旧是<训练指南>上的一道例题.思路大致相同,即设有一个序列S(i),S(i+1),S(i+2)...S(j),d[i,j]为所求的解.当S(i)==S(k),i<k<=j 时,说明在k回到根,那么S(i+1)...S(k-1)构成一棵独立的子树(当然也可能并不是子树).那么d[i,j]就要加上d[i+1,k-1]*d[k,j],不断递增k,每遇到一个k,d[i,j]+=d[i+1,k-1]*d[k,j]直到k>j.最后的d[i,j]就是序列S(i)..S(j)的解.那么题目

UVALive 3713 Astronauts

题意: 有n个宇航员  他们需要完成A.B.C三种任务  年龄>=平均年龄的人可以做A和C  年龄<平均年龄的能做B和C  且宇航员之间有讨厌关系不能一起做任务  要求给出一种分配方案 思路: 一类人有2种选择而且必须选1个  因此想到2-sat  根据年龄和讨厌关系来建边  之后先做可行性判断  确定可以后  求出任意一组可行解  不需要字典序最小 代码: #include<cstdio> #include<cstring> #include<algorithm

UVALive 3713 Astronauts (2-SAT,变形)

题意:有A,B,C三种任务,每个人必获得1个任务,大于等于平均年龄的可以选择A和C,小于平均年龄的可以选择B和C.这些人有一些是互相讨厌的,必须不能执行同任务,问能否安排他们工作?若行,输出任意一组解. 思路: 依然是 2-SAT,只不过换了个样子,建图时不同而已.这里每个人依然有2人选择,也有冲突的出现,问题在如何找出冲突. 首先,无论是哪两人,只要互相讨厌,去抢C,必定冲突.其次,如果是同龄人(同大于等于,或同小于),那么抢他们那个年龄段的任务也会冲突.所以共计2种,每种2条边,即我选的时候