loj 1407(2-sat + 枚举 + 输出一组可行解 )

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=27115

思路:有一个trick要注意:当情况为 2 x y 时,可以推出当y留下时,x也必须留下。然后就是后面的k个限制关系,我们可以3^(k)次方枚举,一旦找到符合条件的就return 。然后就是反向建图,拓扑排序找可行解。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<stack>
  6 #include<queue>
  7 #include<vector>
  8 #include<cmath>
  9 using namespace std;
 10 #define MAXN 2222
 11 
 12 int n,m,k;
 13 struct Node{
 14     int tag;
 15     int num[3];
 16 }node[7];
 17 
 18 vector<vector<int> >g,gg,edge;
 19 
 20 int cnt,bcc_count;
 21 int dfn[MAXN],low[MAXN],color[MAXN];
 22 int degree[MAXN];
 23 bool mark[MAXN];
 24 stack<int>S;
 25 
 26 void Tarjan(int u)
 27 {
 28     low[u]=dfn[u]=++cnt;
 29     mark[u]=true;
 30     S.push(u);
 31     for(int i=0;i<edge[u].size();i++){
 32         int v=edge[u][i];
 33         if(dfn[v]==0){
 34             Tarjan(v);
 35             low[u]=min(low[u],low[v]);
 36         }else if(mark[v]){
 37             low[u]=min(low[u],dfn[v]);
 38         }
 39     }
 40     if(low[u]==dfn[u]){
 41         int v;
 42         bcc_count++;
 43         do{
 44             v=S.top();
 45             S.pop();
 46             mark[v]=false;
 47             color[v]=bcc_count;
 48         }while(u!=v);
 49     }
 50 }
 51 
 52 int opp[MAXN];
 53 bool Check()
 54 {
 55     for(int i=1;i<=n;i++){
 56         if(color[i]==color[i+n])return false;
 57         opp[color[i]]=color[i+n];
 58         opp[color[i+n]]=color[i];
 59     }
 60     return true;
 61 }
 62 
 63 bool Judge()
 64 {
 65     int kk=(int)pow(3.0,k);
 66     for(int i=0;i<kk;i++){
 67         for(int j=1;j<=2*n;j++)edge[j]=g[j];
 68         int j=i,_count=0;
 69         while(_count<k){
 70             int id=j%3;
 71             int x=node[_count].num[id];
 72             if(node[_count].tag==1){
 73                 edge[x+n].push_back(x);
 74             }else 
 75                 edge[x].push_back(x+n);
 76             _count++;
 77             j/=3;
 78         }
 79         cnt=bcc_count=0;
 80         memset(dfn,0,sizeof(dfn));
 81         memset(mark,false,sizeof(mark));
 82         for(int j=1;j<=2*n;j++)if(dfn[j]==0)Tarjan(j);
 83         if(Check())return true;
 84     }
 85     return false;
 86 }
 87 
 88 int vis[MAXN];
 89 void TopSort()
 90 {
 91     queue<int>que;
 92     for(int i=1;i<=bcc_count;i++){
 93         if(degree[i]==0)que.push(i);
 94     }
 95     memset(vis,0,sizeof(vis));
 96     while(!que.empty()){
 97         int u=que.front();
 98         que.pop();
 99         if(vis[u]==0){
100             vis[u]=1;
101             vis[opp[u]]=-1;
102         }
103         for(int i=0;i<gg[u].size();i++){
104             int v=gg[u][i];
105             if(--degree[v]==0)que.push(v);
106         }
107     }
108 }
109 
110 vector<int>ans;
111 void Solve()
112 {
113     gg.clear();
114     gg.resize(2*n+2);
115     memset(degree,0,sizeof(degree));
116     for(int u=1;u<=2*n;u++){
117         for(int i=0;i<edge[u].size();i++){
118             int v=edge[u][i];
119             if(color[u]!=color[v]){
120                 gg[color[v]].push_back(color[u]);
121                 degree[color[u]]++;
122             }
123         }
124     }
125     TopSort();
126     ans.clear();
127     for(int i=1;i<=n;i++)
128         if(vis[color[i]]==1)ans.push_back(i);
129     printf("%d",(int)ans.size());
130     for(int i=0;i<(int)ans.size();i++){
131         printf(" %d",ans[i]);
132     }
133     puts(".");
134 }
135 
136 int main()
137 {
138     int _case,x,y,z,tag,t=1;
139     scanf("%d",&_case);
140     while(_case--){
141         scanf("%d%d%d",&n,&m,&k);
142         g.clear();
143         g.resize(2*n+2);
144         edge.clear();
145         edge.resize(2*n+2);
146         while(m--){
147             scanf("%d%d%d",&tag,&x,&y);
148             if(tag==1)g[x+n].push_back(y),g[y+n].push_back(x);
149             else if(tag==2)g[x+n].push_back(y+n),g[y].push_back(x);
150             else if(tag==3)g[x].push_back(y+n),g[y].push_back(x+n);
151             else g[x].push_back(y+n),g[y].push_back(x+n),g[x+n].push_back(y),g[y+n].push_back(x);
152         }
153         for(int i=0;i<k;i++){
154             scanf("%d%d%d%d",&node[i].tag,&node[i].num[0],&node[i].num[1],&node[i].num[2]);
155         }
156         printf("Case %d: ",t++);
157         if(Judge()){
158             printf("Possible ");
159             Solve();
160         }else 
161             puts("Impossible.");
162     }
163     return 0;
164 }
165         
View Code
原文地址:https://www.cnblogs.com/wally/p/3337535.html