poj 2723 2-sat
其实可以二分的,听说直接输入一扇门的信息,做一次SCC也能爆过,就直接暴力了,呵呵~
每个门有两把锁,这就有了一种关系,假设两把锁是a,b,那么不开a就一定要开b,不开b就一定要开a,即b'->a,a'->b;
另外还有n对矛盾关系,用了a钥匙就不能用b钥匙,a->b',b->a'
然后,强连通求解
#include<stdio.h> #include<string.h> #include<vector> #include<algorithm> using namespace std; const int MAX = 10010; vector<int> edge[MAX]; int st[MAX]; int dfn[MAX],low[MAX]; int top,btype,tdfn;//btype:连通块的个数 int belong[MAX];//点属于哪个连通块 bool ins[MAX]; void dfs(int s) { int i,t; dfn[s]=low[s]=++tdfn; ins[s]=true; st[++top]=s; for(i=0;i<edge[s].size();i++) { t=edge[s][i]; if(!dfn[t]) { dfs(t); if(low[t]<low[s]) low[s]=low[t]; } else if(ins[t] && dfn[t]<low[s]) low[s]=dfn[t]; } if(dfn[s]==low[s]) { btype++; do { t=st[top--]; ins[t]=false; belong[t]=btype; }while(t!=s); } } void SCC(int n) { int i; top=btype=tdfn=0; memset(ins,false,sizeof(ins)); memset(dfn,0,sizeof(dfn)); for(i=1;i<=n;i++) if(!dfn[i]) dfs(i); } int main() { int i,j,k; int n,m; int a,b; while(scanf("%d%d",&n,&m),(n||m)) { for(i=0;i<=4*n;i++) edge[i].clear(); for(i=0;i<n;i++) { scanf("%d%d",&a,&b); a++,b++; edge[a].push_back(b+2*n); edge[b].push_back(a+2*n); } int ans=0; bool flag=true; for(i=0;i<m;i++) { scanf("%d%d",&a,&b); a++,b++; if(flag) { edge[a+2*n].push_back(b); edge[b+2*n].push_back(a); SCC(4*n); for(j=1;j<=2*n;j++) { if(belong[j]==belong[j+2*n]) { flag=false; break; } } if(flag)ans++; } else continue; } printf("%d\n",ans); } return 0; }