首页 > 代码库 > 2-sat

2-sat

Let‘s go home http://acm.hdu.edu.cn/showproblem.php?pid=1824

 

把队长和两个队员当成对称的两个点,有你没我,有我没你。

 

  1 #include<cstdio>  2 #include<cstring>  3 #include<queue>  4 #include<stack>  5 #include<map>  6 #define mt(a,b) memset(a,b,sizeof(a))  7 using namespace std;  8 class TwoSat { ///2-sat判定,solve函数返回是否有解,i结点的对称结点i^为i+n,  9     static const int ME=10010;///边的个数 10     static const int MV=2010;///点的个数 11     struct G { 12         struct E { 13             int u,v,next; 14         } e[ME]; 15         int le,head[MV]; 16         void init() { 17             le=0; 18             mt(head,-1); 19         } 20         void add(int u,int v) { 21             e[le].u=u; 22             e[le].v=v; 23             e[le].next=head[u]; 24             head[u]=le++; 25         } 26     } g; 27     class Tarjan { ///有向图强连通分量缩点o(MV+ME) 28         int Index,Bcnt,num[MV],belong[MV],dfn[MV],low[MV]; 29         bool instack[MV]; 30         stack<int> s; 31         void tarjan(int u) { 32             dfn[u]=low[u]=++Index; 33             instack[u]=true; 34             s.push(u); 35             int v; 36             for(int i=g.head[u]; ~i; i=g.e[i].next) { 37                 v=g.e[i].v; 38                 if(!dfn[v]) { 39                     tarjan(v); 40                     low[u]=min(low[u],low[v]); 41                 } else if(instack[v]) { 42                     low[u]=min(low[u],dfn[v]); 43                 } 44             } 45             if(dfn[u]==low[u]) { 46                 Bcnt++; 47                 do { 48                     v=s.top(); 49                     s.pop(); 50                     instack[v]=false; 51                     belong[v]=Bcnt; 52                     num[Bcnt]++; 53                 } while(u!=v); 54             } 55         } 56     public: 57         G g; 58         void init() { 59             g.init(); 60             Index=Bcnt=0; 61             mt(num,0); 62             mt(dfn,0); 63             mt(low,0); 64             mt(instack,0); 65             while(!s.empty()) s.pop(); 66         } 67         void add(int u,int v) { 68             g.add(u,v); 69         } 70         void solve(int n) {///传入点数,点下标1开始 71             for(int i=1; i<=n; i++) { 72                 if(!dfn[i]) { 73                     tarjan(i); 74                 } 75             } 76         } 77         int getbcnt() {///强连通分量的个数 78             return Bcnt; 79         } 80         int getbelong(int id) {///属于哪个分量,分量下标1开始 81             return belong[id]; 82         } 83         int getnum(int id) {///某个分量的点的个数 84             return num[id]; 85         } 86     } T; 87     class Unitenode { ///缩点 88         G ug; 89         int n,in[MV]; 90         bool mat[MV][MV]; 91         queue<int> q; 92     public: 93         void init(int tn) { 94             n=tn; 95             ug.init(); 96             mt(in,0); 97             for(int i=1;i<=n;i++) 98                 for(int j=1;j<=n;j++) 99                     mat[i][j]=i==j?true:false;100         }101         void add(int u,int v) {102             if(!mat[u][v]) {103                 in[v]++;104                 mat[u][v]=true;105                 ug.add(u,v);106             }107         }108         void solve(int tp[]) {109             while(!q.empty()) q.pop();110             for(int i=1; i<=n; i++) {111                 if(!in[i]) {112                     q.push(i);113                 }114             }115             int ret=1;116             while(!q.empty()) {117                 int u=q.front();118                 q.pop();119                 tp[ret++]=u;120                 for(int i=ug.head[u]; ~i; i=ug.e[i].next) {121                     int v=ug.e[i].v;122                     in[v]--;123                     if(!in[v]) {124                         q.push(v);125                     }126                 }127             }128         }129     } U;130     void unite() {131         U.init(T.getbcnt());132         for(int i=1; i<=n; i++) {133             for(int j=T.g.head[i]; ~j; j=T.g.e[j].next) {134                 U.add(T.getbelong(i),T.getbelong(T.g.e[j].v));135             }136         }137     }138     int n,tp[MV];139     bool flag[MV];140 public:141     void init(int tn) { ///传入判定结点2*n142         n=tn;143         T.init();144     }145     void add(int u,int v) { ///如果取u必须取v结点添加边u->v,下标1开始146         T.add(u,v);147     }148     bool solve() {149         T.solve(n);150         for(int i=1,z=n/2; i<=z; i++) {151             if(T.getbelong(i)==T.getbelong(i+z))return false;152         }153         return true;154     }155     void output(bool ans[]) {///ans[i]==false则选择i结点,否则选择i^结点156         unite();157         U.solve(tp);158         mt(flag,0);159         for(int i=T.getbcnt(); i>0; i--) {160             for(int j=1,y; j<=n; j++) {161                 if(j>n/2)y=j-n/2;162                 else y=j;163                 if(!flag[y]&&T.getbelong(j)==tp[i]) {164                     flag[y]=true;165                     if(j>n/2) {166                         ans[j-n/2]=true;167                     } else {168                         ans[j]=false;169                     }170                 }171             }172         }173     }174 } gx;175 int mp[3010];176 int main() {177     int n,m,x,y,z;178     while(~scanf("%d%d",&n,&m)) {179         gx.init(n*2);180         int myid=1;181         for(int i=0; i<n; i++) {182             scanf("%d%d%d",&x,&y,&z);183             mp[x]=myid;184             mp[y]=myid+n;185             mp[z]=myid+n;186             myid++;187         }188         for(int i=0; i<m; i++) {189             scanf("%d%d",&x,&y);190             x=mp[x];191             y=mp[y];192             gx.add(x,y+(y>n?-n:n));193             gx.add(y,x+(x>n?-n:n));194         }195         if(gx.solve()) {196             puts("yes");197         } else {198             puts("no");199         }200     }201     return 0;202 }
View Code

 

 

Party http://acm.hdu.edu.cn/showproblem.php?pid=3062

根据矛盾关系建图

 

  1 #include<cstdio>  2 #include<cstring>  3 #include<queue>  4 #include<stack>  5 #include<map>  6 #define mt(a,b) memset(a,b,sizeof(a))  7 using namespace std;  8 class TwoSat { ///2-sat判定,solve函数返回是否有解,i结点的对称结点i^为i+n,  9     static const int ME=1000010;///边的个数 10     static const int MV=2010;///点的个数 11     struct G { 12         struct E { 13             int u,v,next; 14         } e[ME]; 15         int le,head[MV]; 16         void init() { 17             le=0; 18             mt(head,-1); 19         } 20         void add(int u,int v) { 21             e[le].u=u; 22             e[le].v=v; 23             e[le].next=head[u]; 24             head[u]=le++; 25         } 26     } g; 27     class Tarjan { ///有向图强连通分量缩点o(MV+ME) 28         int Index,Bcnt,num[MV],belong[MV],dfn[MV],low[MV]; 29         bool instack[MV]; 30         stack<int> s; 31         void tarjan(int u) { 32             dfn[u]=low[u]=++Index; 33             instack[u]=true; 34             s.push(u); 35             int v; 36             for(int i=g.head[u]; ~i; i=g.e[i].next) { 37                 v=g.e[i].v; 38                 if(!dfn[v]) { 39                     tarjan(v); 40                     low[u]=min(low[u],low[v]); 41                 } else if(instack[v]) { 42                     low[u]=min(low[u],dfn[v]); 43                 } 44             } 45             if(dfn[u]==low[u]) { 46                 Bcnt++; 47                 do { 48                     v=s.top(); 49                     s.pop(); 50                     instack[v]=false; 51                     belong[v]=Bcnt; 52                     num[Bcnt]++; 53                 } while(u!=v); 54             } 55         } 56     public: 57         G g; 58         void init() { 59             g.init(); 60             Index=Bcnt=0; 61             mt(num,0); 62             mt(dfn,0); 63             mt(low,0); 64             mt(instack,0); 65             while(!s.empty()) s.pop(); 66         } 67         void add(int u,int v) { 68             g.add(u,v); 69         } 70         void solve(int n) {///传入点数,点下标1开始 71             for(int i=1; i<=n; i++) { 72                 if(!dfn[i]) { 73                     tarjan(i); 74                 } 75             } 76         } 77         int getbcnt() {///强连通分量的个数 78             return Bcnt; 79         } 80         int getbelong(int id) {///属于哪个分量,分量下标1开始 81             return belong[id]; 82         } 83         int getnum(int id) {///某个分量的点的个数 84             return num[id]; 85         } 86     } T; 87     class Unitenode { ///缩点 88         G ug; 89         int n,in[MV]; 90         bool mat[MV][MV]; 91         queue<int> q; 92     public: 93         void init(int tn) { 94             n=tn; 95             ug.init(); 96             mt(in,0); 97             for(int i=1;i<=n;i++) 98                 for(int j=1;j<=n;j++) 99                     mat[i][j]=i==j?true:false;100         }101         void add(int u,int v) {102             if(!mat[u][v]) {103                 in[v]++;104                 mat[u][v]=true;105                 ug.add(u,v);106             }107         }108         void solve(int tp[]) {109             while(!q.empty()) q.pop();110             for(int i=1; i<=n; i++) {111                 if(!in[i]) {112                     q.push(i);113                 }114             }115             int ret=1;116             while(!q.empty()) {117                 int u=q.front();118                 q.pop();119                 tp[ret++]=u;120                 for(int i=ug.head[u]; ~i; i=ug.e[i].next) {121                     int v=ug.e[i].v;122                     in[v]--;123                     if(!in[v]) {124                         q.push(v);125                     }126                 }127             }128         }129     } U;130     void unite() {131         U.init(T.getbcnt());132         for(int i=1; i<=n; i++) {133             for(int j=T.g.head[i]; ~j; j=T.g.e[j].next) {134                 U.add(T.getbelong(i),T.getbelong(T.g.e[j].v));135             }136         }137     }138     int n,tp[MV];139     bool flag[MV];140 public:141     void init(int tn) { ///传入判定结点2*n142         n=tn;143         T.init();144     }145     void add(int u,int v) { ///如果取u必须取v结点添加边u->v,下标1开始146         T.add(u,v);147     }148     bool solve() {149         T.solve(n);150         for(int i=1,z=n/2; i<=z; i++) {151             if(T.getbelong(i)==T.getbelong(i+z))return false;152         }153         return true;154     }155     void output(bool ans[]) {///ans[i]==false则选择i结点,否则选择i^结点156         unite();157         U.solve(tp);158         mt(flag,0);159         for(int i=T.getbcnt(); i>0; i--) {160             for(int j=1,y; j<=n; j++) {161                 if(j>n/2)y=j-n/2;162                 else y=j;163                 if(!flag[y]&&T.getbelong(j)==tp[i]) {164                     flag[y]=true;165                     if(j>n/2) {166                         ans[j-n/2]=true;167                     } else {168                         ans[j]=false;169                     }170                 }171             }172         }173     }174 } gx;175 int main() {176     int n,m,a,b,c,d;177     while(~scanf("%d%d",&n,&m)) {178         gx.init(n*2);179         for(int i=0; i<m; i++) {180             scanf("%d%d%d%d",&a,&b,&c,&d);181             a++;182             b++;183             if(c==0&&d==0) {184                 gx.add(a,b+n);185                 gx.add(b,a+n);186             } else if(c==1&&d==1) {187                 gx.add(a+n,b);188                 gx.add(b+n,a);189             } else if(c==0&&d==1) {190                 gx.add(a,b);191                 gx.add(b+n,a+n);192             } else if(c==1&&d==0) {193                 gx.add(a+n,b+n);194                 gx.add(b,a);195             }196         }197         if(gx.solve()) {198             puts("YES");199         } else {200             puts("NO");201         }202     }203     return 0;204 }
View Code

 

 

D. Ring Road 2 http://codeforces.com/problemset/problem/27/D

 

  1 #include<cstdio>  2 #include<cstring>  3 #include<queue>  4 #include<stack>  5 #include<map>  6 #define mt(a,b) memset(a,b,sizeof(a))  7 using namespace std;  8 class TwoSat { ///2-sat判定,solve函数返回是否有解,i结点的对称结点i^为i+n,  9     static const int ME=1000010;///边的个数 10     static const int MV=2010;///点的个数 11     struct G { 12         struct E { 13             int u,v,next; 14         } e[ME]; 15         int le,head[MV]; 16         void init() { 17             le=0; 18             mt(head,-1); 19         } 20         void add(int u,int v) { 21             e[le].u=u; 22             e[le].v=v; 23             e[le].next=head[u]; 24             head[u]=le++; 25         } 26     } g; 27     class Tarjan { ///有向图强连通分量缩点o(MV+ME) 28         int Index,Bcnt,num[MV],belong[MV],dfn[MV],low[MV]; 29         bool instack[MV]; 30         stack<int> s; 31         void tarjan(int u) { 32             dfn[u]=low[u]=++Index; 33             instack[u]=true; 34             s.push(u); 35             int v; 36             for(int i=g.head[u]; ~i; i=g.e[i].next) { 37                 v=g.e[i].v; 38                 if(!dfn[v]) { 39                     tarjan(v); 40                     low[u]=min(low[u],low[v]); 41                 } else if(instack[v]) { 42                     low[u]=min(low[u],dfn[v]); 43                 } 44             } 45             if(dfn[u]==low[u]) { 46                 Bcnt++; 47                 do { 48                     v=s.top(); 49                     s.pop(); 50                     instack[v]=false; 51                     belong[v]=Bcnt; 52                     num[Bcnt]++; 53                 } while(u!=v); 54             } 55         } 56     public: 57         G g; 58         void init() { 59             g.init(); 60             Index=Bcnt=0; 61             mt(num,0); 62             mt(dfn,0); 63             mt(low,0); 64             mt(instack,0); 65             while(!s.empty()) s.pop(); 66         } 67         void add(int u,int v) { 68             g.add(u,v); 69         } 70         void solve(int n) {///传入点数,点下标1开始 71             for(int i=1; i<=n; i++) { 72                 if(!dfn[i]) { 73                     tarjan(i); 74                 } 75             } 76         } 77         int getbcnt() {///强连通分量的个数 78             return Bcnt; 79         } 80         int getbelong(int id) {///属于哪个分量,分量下标1开始 81             return belong[id]; 82         } 83         int getnum(int id) {///某个分量的点的个数 84             return num[id]; 85         } 86     } T; 87     class Unitenode { ///缩点 88         G ug; 89         int n,in[MV]; 90         bool mat[MV][MV]; 91         queue<int> q; 92     public: 93         void init(int tn) { 94             n=tn; 95             ug.init(); 96             mt(in,0); 97             for(int i=1;i<=n;i++) 98                 for(int j=1;j<=n;j++) 99                     mat[i][j]=i==j?true:false;100         }101         void add(int u,int v) {102             if(!mat[u][v]) {103                 in[v]++;104                 mat[u][v]=true;105                 ug.add(u,v);106             }107         }108         void solve(int tp[]) {109             while(!q.empty()) q.pop();110             for(int i=1; i<=n; i++) {111                 if(!in[i]) {112                     q.push(i);113                 }114             }115             int ret=1;116             while(!q.empty()) {117                 int u=q.front();118                 q.pop();119                 tp[ret++]=u;120                 for(int i=ug.head[u]; ~i; i=ug.e[i].next) {121                     int v=ug.e[i].v;122                     in[v]--;123                     if(!in[v]) {124                         q.push(v);125                     }126                 }127             }128         }129     } U;130     void unite() {131         U.init(T.getbcnt());132         for(int i=1; i<=n; i++) {133             for(int j=T.g.head[i]; ~j; j=T.g.e[j].next) {134                 U.add(T.getbelong(i),T.getbelong(T.g.e[j].v));135             }136         }137     }138     int n,tp[MV];139     bool flag[MV];140 public:141     void init(int tn) { ///传入判定结点2*n142         n=tn;143         T.init();144     }145     void add(int u,int v) { ///如果取u必须取v结点添加边u->v,下标1开始146         T.add(u,v);147     }148     bool solve() {149         T.solve(n);150         for(int i=1,z=n/2; i<=z; i++) {151             if(T.getbelong(i)==T.getbelong(i+z))return false;152         }153         return true;154     }155     void output(bool ans[]) {///ans[i]==false则选择i结点,否则选择i^结点156         unite();157         U.solve(tp);158         mt(flag,0);159         for(int i=T.getbcnt(); i>0; i--) {160             for(int j=1,y; j<=n; j++) {161                 if(j>n/2)y=j-n/2;162                 else y=j;163                 if(!flag[y]&&T.getbelong(j)==tp[i]) {164                     flag[y]=true;165                     if(j>n/2) {166                         ans[j-n/2]=true;167                     } else {168                         ans[j]=false;169                     }170                 }171             }172         }173     }174 } gx;175 const int M=128;176 struct IN {177     int x,y;178 } in[M];179 bool ok(int i,int j) {180     if(in[i].x<in[j].x&&in[j].x<in[i].y&&in[i].y<in[j].y) return true;181     return false;182 }183 bool judge(int i,int j) {184     if(ok(i,j)||ok(j,i)) return true;185     return false;186 }187 bool ans[M];188 int main() {189     int n,m;190     while(~scanf("%d%d",&n,&m)) {191         gx.init(m*2);192         for(int i=1; i<=m; i++) {193             scanf("%d%d",&in[i].x,&in[i].y);194             if(in[i].x>in[i].y) swap(in[i].x,in[i].y);195         }196         for(int i=1; i<=m; i++) {197             for(int j=i+1; j<=m; j++) {198                 if(judge(i,j)) {199 //                    printf("%d %d\n",i,j);200                     gx.add(i,j+m);201                     gx.add(j,i+m);202                     gx.add(i+m,j);203                     gx.add(j+m,i);204                 }205             }206         }207         if(gx.solve()) {208             gx.output(ans);209             for(int i=1; i<=m; i++) {210                 if(ans[i]) printf("i");211                 else       printf("o");212             }213             puts("");214         } else {215             puts("Impossible");216         }217     }218     return 0;219 }
View Code

 

 

 

end

2-sat