uvalive 3713 Astronauts
题意:
现在要安排一些宇航员去星球勘探。有3个星球,分别是J第一大的月亮A,J第二大的月亮B,S第一大的月亮C。
规定年轻的宇航员不能去A,年长的宇航员不能去B,C任何人都可以去。
现在有一些宇航员之间有矛盾,他们不能去相同的星球。
现在问可否安排出这样的方案满足条件,如果有,那么就输出每个宇航员去的星球,没有就说明不可能。
思路:
2-SAT问题
对于年轻的宇航员,去B为真,去C为假
对于年长的宇航员,去A为真,去C为假
首先考虑对于不同类型的宇航员i和j,只要他们不在同一个星球C上就满足条件,即Xi ∨ Xj为真就满足,利用这个条件加边
但是对于同一个类型的宇航员i和j,他们不在同一个星球才满足条件,这个条件要求Xi 和Xj当中必定一个为真,一个为假,那么如何刻画呢?那就是两个当中至少一个为真,至少有一个为假,用符号表示即为Xi V Xj,┐Xi ∨┐Xj 两个条件同时为真,那么进行两次加边就可以了。
代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <vector> 5 #include <algorithm> 6 using namespace std; 7 8 const int maxn = 100005; 9 int a[maxn]; 10 11 struct twosat 12 { 13 int n; 14 vector<int> g[maxn*2]; 15 bool mark[maxn*2]; 16 int s[maxn*2],c; 17 18 bool dfs(int x) 19 { 20 if (mark[x^1]) return false; 21 if (mark[x]) return true; 22 23 mark[x] = true; 24 25 s[c++] = x; 26 27 for (int i = 0;i < g[x].size();i++) 28 { 29 if (!dfs(g[x][i])) return false; 30 } 31 32 return true; 33 } 34 35 void init(int n) 36 { 37 this -> n = n; 38 39 for (int i = 0;i <= n * 2;i++) g[i].clear(); 40 41 memset(mark,0,sizeof(mark)); 42 } 43 44 void add_clause(int x,int xval,int y,int yval) 45 { 46 x = 2 * x + xval; 47 y = 2 * y + yval; 48 49 g[x^1].push_back(y); 50 g[y^1].push_back(x); 51 } 52 53 bool solve() 54 { 55 for (int i = 0;i < 2 * n;i += 2) 56 { 57 if (!mark[i] && !mark[i+1]) 58 { 59 c = 0; 60 61 if (!dfs(i)) 62 { 63 while (c > 0) mark[s[--c]] = 0; 64 65 if (!dfs(i+1)) return false; 66 } 67 } 68 } 69 70 return true; 71 } 72 } twosat; 73 74 int main() 75 { 76 int n,m; 77 //int kase = 0; 78 79 while (scanf("%d%d",&n,&m) != EOF) 80 { 81 if (n == 0 && m == 0) break; 82 83 int ave = 0; 84 85 for (int i = 0;i < n;i++) 86 { 87 scanf("%d",&a[i]); 88 ave += a[i]; 89 } 90 91 //ave /= n; 92 93 twosat.init(n); 94 95 for (int i = 0;i < m;i++) 96 { 97 int x,y; 98 99 scanf("%d%d",&x,&y); 100 101 x--,y--; 102 103 //if (x == y) continue; 104 105 if (a[x] * n < ave && a[y] * n < ave) 106 { 107 twosat.add_clause(x,1,y,1); 108 twosat.add_clause(x,0,y,0); 109 } 110 else if (a[x] * n >= ave && a[y] * n >= ave) 111 { 112 twosat.add_clause(x,1,y,1); 113 twosat.add_clause(x,0,y,0); 114 } 115 else 116 { 117 twosat.add_clause(x,1,y,1); 118 } 119 } 120 121 if (twosat.solve()) 122 { 123 for (int i = 0;i < n;i++) 124 { 125 if (a[i] * n >= ave) 126 { 127 if (twosat.mark[2*i+1]) printf("A\n"); 128 else printf("C\n"); 129 } 130 else 131 { 132 if (twosat.mark[2*i+1]) printf("B\n"); 133 else printf("C\n"); 134 } 135 } 136 } 137 else 138 { 139 printf("No solution.\n"); 140 } 141 142 //printf("\n"); 143 } 144 145 return 0; 146 }
康复训练中~欢迎交流!