2-SAT 学习笔记
总结了下就三句话:
1.确定集合,以及每个集合必须二选一的状态
2.枚举相关的集合,再枚举相关集合可能出现的会影响状态选择的矛盾情况
3.以矛盾为前提,确定的情况才加边
感觉矛盾可以理解为“无法导致条件成立的情况”
所以很多时候要先确定一个条件,然后把不能使之成立的情况找出来,建图后判定
1.POJ 3227
每条连线当作是一个集合,每个集合的状态是在圆内或者圆外,任意两个集合都可能出现矛盾,矛盾是位置交叉
#include"cstdio" #include"queue" #include"cmath" #include"stack" #include"iostream" #include"algorithm" #include"cstring" #include"queue" #include"map" #include"set" #include"vector" #include"bitset" #define LL long long #define ull unsigned long long #define mems(a,b) memset(a,b,sizeof(a)) #define mdzz int mid=(L+R)>>1 #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; const int N = 2e5+50; const int M = 1e5+5; const LL MOD = 1e9+7; const int INF = 0x3f3f3f3f; int block,tp,tot,id; int low[N],dfn[N],ins[N]; int st[N],belong[N]; int first[N]; struct node{ int e,next; node(){} node(int a,int b):e(a),next(b){} }edge[N];; void init(){ tot=0;id=0;tp=0; mems(first,-1); mems(dfn,0); mems(ins,0); } void addedge(int u,int v){ edge[tot]=node(v,first[u]); first[u]=tot++; } void tarjan(int u){ low[u]=dfn[u]=++id; ins[u]=1; st[++tp]=u; for(int i=first[u];i!=-1;i=edge[i].next){ int v=edge[i].e; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(ins[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]){ block++; int v; do{ v=st[tp--]; ins[v]=0; belong[v]=block; //sz[block]++; } while(v!=u); } } int n,m; int u[N],v[N]; bool check(int i,int j){ if(u[i]>u[j]&&u[i]<v[j]&&v[i]>v[j]) return true; return false; } int main(){ //freopen("in.txt","r",stdin); while(~scanf("%d%d",&n,&m)){ init(); for(int i=0;i<m;i++){ scanf("%d%d",&u[i],&v[i]); u[i]++;v[i]++; if(u[i]>v[i]) swap(u[i],v[i]); } for(int i=0;i<m;i++) for(int j=i+1;j<m;j++) if(check(i,j)||check(j,i)){ addedge(i<<1,j<<1|1); addedge(j<<1,i<<1|1); addedge(i<<1|1,j<<1); addedge(j<<1|1,i<<1); } for(int i=0;i<2*m;i++) if(!dfn[i]) tarjan(i); int f=1; for(int i=0;i<2*m;i++) if(belong[i]==belong[i^1]){ f=0; break; } if(f) printf("panda is telling the truth...\n"); else printf("the evil panda is lying again\n"); } return 0; }
2.POJ 3683
每个婚礼时间当作一个集合,每个集合的两个状态是在开头或者结尾举办仪式,任意两个集合都可能出现矛盾,矛盾是时间交叉
#include"cstdio" #include"queue" #include"cmath" #include"stack" #include"iostream" #include"algorithm" #include"cstring" #include"queue" #include"map" #include"set" #include"vector" #include"bitset" #define LL long long #define ull unsigned long long #define mems(a,b) memset(a,b,sizeof(a)) #define mdzz int mid=(L+R)>>1 #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; const int N = 4e3+50; const int M = 1e6+5; const LL MOD = 1e9+7; const int INF = 0x3f3f3f3f; int block,tp,tot,id; int low[N],dfn[N],ins[N]; int st[N],belong[N]; int first[N],deg[N]; struct node{ int s,e,next; node(){} node(int a,int b,int c):s(a),e(b),next(c){} }edge[M<<2]; void init(){ tot=0;id=0;tp=0; mems(first,-1); mems(dfn,0); mems(ins,0); mems(deg,0); } void addedge(int u,int v){ //cout<<u<<' '<<v<<endl; edge[tot]=node(u,v,first[u]); first[u]=tot++; } void tarjan(int u){ low[u]=dfn[u]=++id; ins[u]=1; st[++tp]=u; for(int i=first[u];i!=-1;i=edge[i].next){ int v=edge[i].e; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(ins[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]){ block++; int v; do{ v=st[tp--]; ins[v]=0; belong[v]=block; //sz[block]++; } while(v!=u); } } int n,m; int t[N]; struct Node{ int h,m; int id(){ return h*60+m; } void display(){ if(h<10) printf("0"); printf("%d:",h); if(m<10) printf("0"); printf("%d",m); } }s[N],e[N],tmp; bool check(Node i,Node j,Node k,Node p){ if(j.id()<=k.id()||p.id()<=i.id()) return false; return true; } Node _get(Node a,int x){ a.m+=x; while(a.m<0) a.h--,a.m+=60; while(a.h<0) a.h+=24; a.h+=a.m/60; a.m%=60; return a; } //vector<int> Ant[N],topo; int Ant[N]; queue<int> q; void rebuild(){ for(int i=0;i<2*n;i++) Ant[belong[i]]=belong[i^1]; //Ant[belong[i]].push_back(belong[i^1]); int tot2=tot; mems(first,-1); tot=0; for(int i=0;i<tot2;i++){ if(belong[edge[i].s]==belong[edge[i].e]) continue; deg[belong[edge[i].s]]++; addedge(belong[edge[i].e],belong[edge[i].s]); } } int col[N]; void toposort(){ mems(col,0); //topo.clear(); while(!q.empty()) q.pop(); for(int i=1;i<=block;i++) if(!deg[i]) q.push(i); while(!q.empty()){ int u=q.front();q.pop(); //topo.push_back(u); if(!col[u]){ col[u]=1; col[Ant[u]]=-1; } for(int i=first[u];i!=-1;i=edge[i].next){ int v=edge[i].e; deg[v]--; if(!deg[v]) q.push(v); } } } int main(){ //freopen("in.txt","r",stdin); while(~scanf("%d",&n)){ init(); for(int i=0;i<n;i++) scanf("%d:%d %d:%d %d",&s[i].h,&s[i].m,&e[i].h,&e[i].m,&t[i]); for(int i=0;i<n;i++) for(int j=i+1;j<n;j++){ if(check(s[i],_get(s[i],t[i]),s[j],_get(s[j],t[j]))){ addedge(i<<1,j<<1|1); addedge(j<<1,i<<1|1); } if(check(s[i],_get(s[i],t[i]),_get(e[j],-t[j]),e[j])){ addedge(i<<1,j<<1); addedge(j<<1|1,i<<1|1); } if(check(_get(e[i],-t[i]),e[i],s[j],_get(s[j],t[j]))){ addedge(i<<1|1,j<<1|1); addedge(j<<1,i<<1); } if(check(_get(e[i],-t[i]),e[i],_get(e[j],-t[j]),e[j])){ addedge(i<<1|1,j<<1); addedge(j<<1|1,i<<1); } } for(int i=0;i<2*n;i++) if(!dfn[i]) tarjan(i); int f=1; for(int i=0;i<2*n;i+=2) if(belong[i]==belong[i+1]){ f=0; break; } //for(int i=0;i<2*n;i++) cout<<i<<' '<<belong[i]<<endl; if(!f){ printf("NO\n"); continue; } else printf("YES\n"); rebuild(); toposort(); for(int i=0;i<n;i++){ if(col[belong[i<<1]]==1){ s[i].display();printf(" "); tmp=_get(s[i],t[i]); tmp.display();printf("\n"); } else{ tmp=_get(e[i],-t[i]); tmp.display();printf(" "); e[i].display();printf("\n"); } } } return 0; }
3.POJ 3678
每个点当作一个集合,每个集合的两个状态是0或者1,有边相连的两个集合才可能出现矛盾,矛盾的情况是不符合运算规则
#include"cstdio" #include"queue" #include"cmath" #include"stack" #include"iostream" #include"algorithm" #include"cstring" #include"queue" #include"map" #include"set" #include"vector" #include"bitset" #define LL long long #define ull unsigned long long #define mems(a,b) memset(a,b,sizeof(a)) #define mdzz int mid=(L+R)>>1 #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; const int N = 4e3+50; const int M = 4e6+5; const LL MOD = 1e9+7; const int INF = 0x3f3f3f3f; int block,tp,tot,id; int low[N],dfn[N],ins[N]; int st[N],belong[N]; int first[N],deg[N]; struct node{ int s,e,next; node(){} node(int a,int b,int c):s(a),e(b),next(c){} }edge[M]; void init(){ tot=0;id=0;tp=0; block=0; mems(first,-1); mems(dfn,0); mems(ins,0); mems(deg,0); } void addedge(int u,int v){ edge[tot]=node(u,v,first[u]); first[u]=tot++; } void tarjan(int u){ low[u]=dfn[u]=++id; ins[u]=1; st[++tp]=u; for(int i=first[u];i!=-1;i=edge[i].next){ int v=edge[i].e; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(ins[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]){ block++; int v; do{ v=st[tp--]; ins[v]=0; belong[v]=block; //sz[block]++; } while(v!=u); } } int n,m; char op[5]; int main(){ //freopen("in.txt","r",stdin); while(~scanf("%d%d",&n,&m)){ init(); int u,v,w,x,f=1; for(int i=0;i<m;i++){ scanf("%d%d%d%s",&u,&v,&x,op); if(op[0]=='O'){ if(x){ addedge(u<<1,v<<1|1); addedge(v<<1,u<<1|1); } else{ addedge(u<<1|1,u<<1); addedge(v<<1|1,v<<1); } } else if(op[0]=='X'){ if(x){ addedge(u<<1,v<<1|1); addedge(v<<1,u<<1|1); addedge(u<<1|1,v<<1); addedge(v<<1|1,u<<1); } else{ addedge(u<<1,v<<1); addedge(v<<1,u<<1); addedge(u<<1|1,v<1|1); addedge(v<<1|1,u<<1|1); } } else if(op[0]=='A'){ if(x){ addedge(u<<1,u<<1|1); addedge(v<<1,v<<1|1); } else{ addedge(v<<1|1,u<<1); addedge(u<<1|1,v<<1); } } } for(int i=0;i<n*2;i++) if(!dfn[i]) tarjan(i); for(int i=0;i<2*n;i+=2) if(belong[i]==belong[i+1]){ f=0; break; } if(f) printf("YES\n"); else printf("NO\n"); } return 0; }
4.POJ 2723
捆绑的两把钥匙当作一个集合,每个集合的两个状态是使用其中的某一把
考虑当前门的两把锁X和Y,钥匙分别是A和B,则与其捆绑的为A'和B'
由于对于捆绑的两把钥匙我只能选择其中一把,若要开当前的门,A和B我至少要选择一把,那导致A和B都无法选择的情况就是所要找的矛盾
也就是说选择了A'和B'的情况
所以A'和B'是不能同时选择的状态,所以加边A->B',B->A'
#include"cstdio" #include"queue" #include"cmath" #include"stack" #include"iostream" #include"algorithm" #include"cstring" #include"queue" #include"map" #include"set" #include"vector" #include"bitset" #define LL long long #define ull unsigned long long #define mems(a,b) memset(a,b,sizeof(a)) #define mdzz int mid=(L+R)>>1 #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; const int N = 1e4+50; const int M = 1e5+5; const LL MOD = 1e9+7; const int INF = 0x3f3f3f3f; int block,tp,tot,id; int low[N],dfn[N],ins[N]; int st[N],belong[N]; int first[N]; int n,m; struct node{ int s,e,next; node(){} node(int a,int b,int c):s(a),e(b),next(c){} }edge[M]; void init(){ tot=0;id=0;tp=0; block=0; mems(first,-1); mems(dfn,0); mems(ins,0); } void addedge(int u,int v){ //cout<<u<<' '<<v<<endl; edge[tot]=node(u,v,first[u]); first[u]=tot++; } void tarjan(int u){ low[u]=dfn[u]=++id; ins[u]=1; st[++tp]=u; for(int i=first[u];i!=-1;i=edge[i].next){ int v=edge[i].e; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(ins[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]){ block++; int v; do{ v=st[tp--]; ins[v]=0; belong[v]=block; //sz[block]++; } while(v!=u); } } int mat[N],loc[N<<1][2]; int u,v; bool check(int mid){ init(); for(int i=0;i<mid;i++){ addedge(loc[i][0],mat[loc[i][1]]); addedge(loc[i][1],mat[loc[i][0]]); } for(int i=0;i<2*n;i++) if(!dfn[i]) tarjan(i); for(int i=0;i<2*n;i++) if(belong[i]==belong[mat[i]]) return false; return true; } int main(){ //freopen("in.txt","r",stdin); while(scanf("%d%d",&n,&m)&&(n||m)){ //init(); for(int i=0;i<n;i++){ scanf("%d%d",&u,&v); mat[u]=v;mat[v]=u; } for(int i=0;i<m;i++) scanf("%d%d",&loc[i][0],&loc[i][1]); int ans=0; int low=0,high=m,mid; //check(mid); while(low<=high){ mid=(low+high)>>1; if(check(mid)){ ans=mid; low=mid+1; } else high=mid-1; //cout<<mid<<endl; } printf("%d\n",ans); } return 0; }
5.POJ 2749
每头牛的两种选择当作一个集合,每个集合的状态是选择其中的某一个中转,矛盾的情况是题目中给的以及对于每两个点的四种连接情况中距离大于枚举的maxdis的时候
#include"cstdio" #include"queue" #include"cmath" #include"stack" #include"iostream" #include"algorithm" #include"cstring" #include"queue" #include"map" #include"set" #include"vector" #include"bitset" #define LL long long #define ull unsigned long long #define mems(a,b) memset(a,b,sizeof(a)) #define mdzz int mid=(L+R)>>1 #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; const int N = 1e3+50; const int M = 1e6+100000; const LL MOD = 1e9+7; const int INF = 0x3f3f3f3f; int block,tp,tot,id; int low[N],dfn[N],ins[N]; int st[N],belong[N]; int first[N]; int n,m; struct node{ int s,e,next; node(){} node(int a,int b,int c):s(a),e(b),next(c){} }edge[M]; void init(){ tot=0;id=0;tp=0; block=0; mems(first,-1); mems(dfn,0); mems(ins,0); } void addedge(int u,int v){ edge[tot]=node(u,v,first[u]); first[u]=tot++; } void tarjan(int u){ low[u]=dfn[u]=++id; ins[u]=1; st[++tp]=u; for(int i=first[u];i!=-1;i=edge[i].next){ int v=edge[i].e; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(ins[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]){ block++; int v; do{ v=st[tp--]; ins[v]=0; belong[v]=block; //sz[block]++; } while(v!=u); } } struct Point{ int x,y; }p[N],s,e; int dis(Point a,Point b){ return abs(a.x-b.x)+abs(a.y-b.y); } int u,v,A,B; int a[N][2],b[N][2]; bool check(int mid){ init(); for(int i=0;i<A;i++){ addedge(a[i][0]<<1,a[i][1]<<1|1); addedge(a[i][0]<<1|1,a[i][1]<<1); addedge(a[i][1]<<1,a[i][0]<<1|1); addedge(a[i][1]<<1|1,a[i][0]<<1); } for(int i=0;i<B;i++){ addedge(b[i][0]<<1,b[i][1]<<1); addedge(b[i][0]<<1|1,b[i][1]<<1|1); addedge(b[i][1]<<1,b[i][0]<<1); addedge(b[i][1]<<1|1,b[i][0]<<1|1); } for(int i=0;i<n;i++) for(int j=i+1;j<n;j++){ if(dis(s,p[i])+dis(s,p[j])>mid){ addedge(i<<1,j<<1|1); addedge(j<<1,i<<1|1); } if(dis(e,p[i])+dis(e,p[j])>mid){ addedge(i<<1|1,j<<1); addedge(j<<1|1,i<<1); } if(dis(s,p[i])+dis(e,p[j])+dis(s,e)>mid){ addedge(i<<1,j<<1); addedge(j<<1|1,i<<1|1); } if(dis(e,p[i])+dis(s,p[j])+dis(s,e)>mid){ addedge(i<<1|1,j<<1|1); addedge(j<<1,i<<1); } } for(int i=0;i<2*n;i++) if(!dfn[i]) tarjan(i); for(int i=0;i<2*n;i+=2) if(belong[i]==belong[i+1]) return false; return true; } int main(){ //freopen("in.txt","r",stdin); while(~scanf("%d%d%d",&n,&A,&B)){ //init(); scanf("%d%d%d%d",&s.x,&s.y,&e.x,&e.y); for(int i=0;i<n;i++) scanf("%d%d",&p[i].x,&p[i].y); for(int i=0;i<A;i++) scanf("%d%d",&a[i][0],&a[i][1]),a[i][0]--,a[i][1]--; for(int i=0;i<B;i++) scanf("%d%d",&b[i][0],&b[i][1]),b[i][0]--,b[i][1]--; int low=0,high=INF,mid,ans=-1; while(low<=high){ mid=(high-low)/2+low; if(check(mid)){ ans=mid; high=mid-1; } else low=mid+1; } printf("%d\n",ans); } return 0; }
6.POJ 2296
每个点的两种选择当作一个集合,每个集合的状态是在上方或者在下方,矛盾的情况是矩形是否相交
#include"cstdio" #include"queue" #include"cmath" #include"stack" #include"iostream" #include"algorithm" #include"cstring" #include"queue" #include"map" #include"set" #include"vector" #include"bitset" #define LL long long #define ull unsigned long long #define mems(a,b) memset(a,b,sizeof(a)) #define mdzz int mid=(L+R)>>1 #define ls pos<<1 #define rs pos<<1|1 #define lson L,mid,pos<<1 #define rson mid+1,R,pos<<1|1 #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; const int N = 2e3+5; const int M = 1e5+5; const LL MOD = 1e9+7; const int INF = 0x3f3f3f3f; struct node{ int x,y; }p[N]; bool cmp(node a,node b){ if(a.x==b.x) return a.y<b.y; return a.x<b.x; } int block,tp,tot,id; int low[N],dfn[N],ins[N]; int st[N],belong[N]; int first[N]; struct Node{ int e,next; Node(){} Node(int a,int b):e(a),next(b){} }edge[M]; void addedge(int u,int v){ //cout<<u<<' '<<v<<endl; edge[tot]=Node(v,first[u]); first[u]=tot++; } void init(){ tot=0;id=0;tp=0; block=0; mems(first,-1); mems(dfn,0); mems(ins,0); } void tarjan(int u){ low[u]=dfn[u]=++id; ins[u]=1; st[++tp]=u; for(int i=first[u];i!=-1;i=edge[i].next){ int v=edge[i].e; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(ins[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]){ block++; int v; do{ v=st[tp--]; ins[v]=0; belong[v]=block; //sz[block]++; } while(v!=u); } } int T,n; bool check(int mid){ init(); for(int i=0;i<n;i++) for(int j=i+1;j<n;j++){ if(abs(p[j].y-p[i].y)>=2*mid||abs(p[j].x-p[i].x)>=mid) continue; if(p[i].y<p[j].y){ if(p[j].y-p[i].y>=mid){ addedge(i+n,j+n); addedge(j,i); } else{ addedge(i,j+n); addedge(j+n,i); addedge(i+n,i); addedge(j,j+n); } } else if(p[i].y>p[j].y){ if(p[i].y-p[j].y>=mid){ addedge(j+n,i+n); addedge(i,j); } else{ addedge(i+n,j); addedge(j,i+n); addedge(i,i+n); addedge(j+n,j); } } else { addedge(i,j+n); addedge(i+n,j); addedge(j+n,i); addedge(j,i+n); } } for(int i=0;i<2*n;i++) if(!dfn[i]) tarjan(i); for(int i=0;i<2*n;i+=2) if(belong[i]==belong[i+1]) return false; return true; } int main(){ //freopen("in.txt","r",stdin); scanf("%d",&T); while(T--){ scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d%d",&p[i].x,&p[i].y); sort(p,p+n,cmp); int low=0,high=INF,mid,ans=0; while(low<=high){ mid=(low+high)>>1; if(check(mid)){ ans=mid; low=mid+1; } else high=mid-1; } //check(2); printf("%d\n",ans); } return 0; }
7. HDU 3622
每个炸弹的两种位置当作一个集合,矛盾的情况是两个炸弹影响范围相交(不知道为什么写成+n模式的就会挂,写异或模式就行。。难道是因为长得丑?
#include"cstdio" #include"queue" #include"cmath" #include"stack" #include"iostream" #include"algorithm" #include"cstring" #include"queue" #include"map" #include"set" #include"vector" #include"bitset" #define LL long long #define ull unsigned long long #define mems(a,b) memset(a,b,sizeof(a)) #define mdzz int mid=(L+R)>>1 #define ls pos<<1 #define rs pos<<1|1 #define lson L,mid,pos<<1 #define rson mid+1,R,pos<<1|1 #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; const int N = 505; const int M = 8e4+5; const LL MOD = 1e9+7; const int INF = 0x3f3f3f3f; int block,tp,tot,id; int low[N],dfn[N],ins[N]; int st[N],belong[N]; int first[N]; struct node{ int e,next; node(){} node(int a,int b):e(a),next(b){} }edge[M]; struct Node{ double x,y; void read(){ scanf("%lf%lf",&x,&y); } }p[N]; void init(){ tot=0;id=0;tp=0; block=0; mems(dfn,0); mems(ins,0); mems(first,-1); mems(low,0); } void addedge(int u,int v){ edge[tot]=node(v,first[u]); first[u]=tot++; } void tarjan(int u){ low[u]=dfn[u]=++id; ins[u]=1; st[++tp]=u; for(int i=first[u];i!=-1;i=edge[i].next){ int v=edge[i].e; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(ins[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]){ block++; int v; do{ v=st[tp--]; ins[v]=0; belong[v]=block; //sz[block]++; } while(v!=u); } } int n; double dis(Node a,Node b){ return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } bool check(double mid){ init(); for(int i=0;i<n*2;i++) for(int j=i+1;j<n*2;j++){ if(dis(p[i],p[j])<mid){ addedge(i,j^1); addedge(j,i^1); } } for(int i=0;i<n*2;i++) if(!dfn[i]) tarjan(i); for(int i=0;i<n*2;i+=2) if(belong[i]==belong[i+1]) return false; return true; } int main(){ //freopen("in.txt","r",stdin); while(~scanf("%d",&n)){ for(int i=0;i<n;i++) //p[i].read(),p[i+n].read(); scanf("%lf%lf%lf%lf",&p[i*2].x,&p[i*2].y,&p[i*2+1].x,&p[i*2+1].y); double low=0,high=1e5,mid,ans=0; while(high-low>1e-4){ mid=(low+high)/2.0; if(check(mid)){ ans=mid; low=mid; } else high=mid; } printf("%.2f\n",ans/2); } return 0; }
8. HDU 1814
论文题,但是要输出最小字典序答案,只能暴力O(n*m)
#include"cstdio" #include"queue" #include"cmath" #include"stack" #include"iostream" #include"algorithm" #include"cstring" #include"queue" #include"map" #include"set" #include"vector" #include"bitset" #define LL long long #define ull unsigned long long #define mems(a,b) memset(a,b,sizeof(a)) #define mdzz int mid=(L+R)>>1 #define ls pos<<1 #define rs pos<<1|1 #define lson L,mid,pos<<1 #define rson mid+1,R,pos<<1|1 #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; const int N = 2e4+5; const int M = 5e4+5; const LL MOD = 1e9+7; const int INF = 0x3f3f3f3f; int block,tp,tot,id; int low[N],dfn[N],ins[N]; int st[N],belong[N]; int first[N],col[N]; int n,m,u,v; struct node{ int s,e,next; node(){} node(int a,int b,int c):s(a),e(b),next(c){} }edge[M]; void init(){ tot=0; mems(first,-1); mems(col,-1); } void addedge(int u,int v){ //cout<<u<<' '<<v<<endl; edge[tot]=node(u,v,first[u]); first[u]=tot++; } ///1 选 0 不选 int ans[N],cnt; bool dfs(int u){ if(col[u]==1) return true; if(col[u]==0) return false; col[u]=1;col[u^1]=0;ans[cnt++]=u; for(int i=first[u];i!=-1;i=edge[i].next){ int v=edge[i].e; if(!dfs(v)){ //col[u]=col[u^1]=-1; return false; } } return true; } void solve(){ for(int i=0;i<2*n;i++) if(col[i]==-1){ cnt=0; if(!dfs(i)){ for(int j=0;j<cnt;j++) col[ans[j]]=col[ans[j]^1]=-1; cnt=0; if(!dfs(i^1)){ printf("NIE\n"); return; } } } for(int i=0;i<2*n;i++) if(col[i]==1) printf("%d\n",i+1); } int main(){ //freopen("in.txt","r",stdin); while(~scanf("%d%d",&n,&m)){ init(); for(int i=0;i<m;i++){ scanf("%d%d",&u,&v); u--;v--; addedge(u,v^1); addedge(v,u^1); } solve(); } return 0; }
9.HDU 4115
由于是要求不能输,所以每局只能赢或平两种状态
令A表示赢的出法,A'表示平局的出法
若要求两局出法相同,枚举两局的四种出法,比如若A!=B,显然两局不能都赢,则加边A->B',其他三种情况类似
要求不同出法的情况与上面类似
#include"cstdio" #include"queue" #include"cmath" #include"stack" #include"iostream" #include"algorithm" #include"cstring" #include"queue" #include"map" #include"set" #include"vector" #include"bitset" #define LL long long #define ull unsigned long long #define mems(a,b) memset(a,b,sizeof(a)) #define mdzz int mid=(L+R)>>1 #define ls pos<<1 #define rs pos<<1|1 #define lson L,mid,pos<<1 #define rson mid+1,R,pos<<1|1 #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; const int N = 2e4+5; const int M = 2e5+5; const LL MOD = 1e9+7; const int INF = 0x3f3f3f3f; int block,tp,tot,id; int low[N],dfn[N],ins[N]; int st[N],belong[N]; int first[N]; struct node{ int e,next; node(){} node(int a,int b):e(a),next(b){} }edge[M]; void init(){ tot=0;id=0;tp=0; block=0; mems(first,-1); mems(dfn,0); mems(ins,0); } void addedge(int u,int v){ edge[tot]=node(v,first[u]); first[u]=tot++; } void tarjan(int u){ low[u]=dfn[u]=++id; ins[u]=1; st[++tp]=u; for(int i=first[u];i!=-1;i=edge[i].next){ int v=edge[i].e; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(ins[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]){ block++; int v; do{ v=st[tp--]; ins[v]=0; belong[v]=block; //sz[block]++; } while(v!=u); } } int cas=1,T,n,m,u,v,k; int b[N]; int bet[4]={0,2,3,1}; ///bet[i]=j j can win i //int win[4]={0,3,1,2}; ///win[i]=j i can win j void solve(){ for(int i=0;i<2*n;i++) if(!dfn[i]) tarjan(i); for(int i=0;i<2*n;i+=2) if(belong[i]==belong[i+1]){ printf("no\n"); return ; } printf("yes\n"); } int main(){ //freopen("in.txt","r",stdin); scanf("%d",&T); while(T--){ init(); scanf("%d%d",&n,&m); for(int i=0;i<n;i++) scanf("%d",&b[i]); for(int i=0;i<m;i++){ scanf("%d%d%d",&u,&v,&k); u--;v--; if(!k){ if(bet[b[u]]!=bet[b[v]]){ addedge(u<<1,v<<1|1); addedge(v<<1,u<1|1); } if(bet[b[u]]!=b[v]){ addedge(u<<1,v<<1); addedge(v<<1|1,u<<1|1); } if(b[u]!=bet[b[v]]){ addedge(u<<1|1,v<<1|1); addedge(v<<1,u<<1); } if(b[u]!=b[v]){ addedge(u<<1|1,v<<1); addedge(v<<1|1,u<<1); } } else{ if(bet[b[u]]==bet[b[v]]){ addedge(u<<1,v<<1|1); addedge(v<<1,u<1|1); } if(bet[b[u]]==b[v]){ addedge(u<<1,v<<1); addedge(v<<1|1,u<<1|1); } if(b[u]==bet[b[v]]){ addedge(u<<1|1,v<<1|1); addedge(v<<1,u<<1); } if(b[u]==b[v]){ addedge(u<<1|1,v<<1); addedge(v<<1|1,u<<1); } } } printf("Case #%d: ",cas++); solve(); } return 0; }
对建图还是有些时候比较懵逼。。还太弱