標籤:style blog http color os io for ar
題意:給出一些宇航員他們的年齡,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或非Aj)並(Ai或Aj)
如果他們是不同組的,那麼只要他們都不是C任務就行,即非(非Ai並非Aj)等價於(Ai或Aj)
這樣就可以用2SAT做了。注意平均年齡x要用浮點數。
我用的是LRJ的模板,2i表示Ai=false,2i+1表示Ai=true
#include <cstdio>#include <cmath>#include <vector>#include <cstring>using namespace std;const int maxn =100005;struct TwoSAT{ int n; vector<int> G[maxn*2]; bool mark[maxn*2]; int S[maxn*2],c; bool dfs(int x) { if(mark[x^1]) return false; if(mark[x]) return true; mark[x]=true; S[c++]=x; for(int i=0; i<G[x].size(); ++i) if(!dfs(G[x][i])) return false; return true; } void init(int n) { this->n=n; for(int i=0; i<n*2; ++i) G[i].clear(); memset(mark,0,sizeof(mark)); } void add_clause(int x,int xval,int y,int yval) { x=x*2+xval; y=y*2+yval; G[x^1].push_back(y); G[y^1].push_back(x); } bool solve() { for(int i=0; i<n*2; i+=2) { if(!mark[i]&&!mark[i+1]) { c=0; if(!dfs(i)) { while(c>0) mark[S[--c]]=false; if(!dfs(i+1)) return false; } } } return true; }};TwoSAT solver;int age[100005];int main(){ int n,m; while(scanf("%d%d",&n,&m)!=EOF) { if(!n&&!m) break; double x=0; for(int i=0; i<n; ++i) { scanf("%d",&age[i]); x+=age[i]; } x/=n; solver.init(n); for(int i=0; i<m; ++i) { int a,b; scanf("%d%d",&a,&b); a--; b--; if((age[a]>=x&&age[b]>=x)||(age[a]<x&&age[b]<x)) { solver.add_clause(a,0,b,0); solver.add_clause(a,1,b,1); } else solver.add_clause(a,1,b,1); } if(!solver.solve()) puts("No solution."); else { for(int i=0; i<2*n; i+=2) if(solver.mark[i]) printf("C\n"); else printf("%c\n",age[i/2]>=x?‘A‘:‘B‘); } } return 0;}View Code