码迷,mamicode.com
首页 > 其他好文 > 详细

2-SAT问题的解决方案

时间:2018-08-11 01:33:51      阅读:195      评论:0      收藏:0      [点我收藏+]

标签:div   后半程   next   不能   选择   ||   include   name   新建   

先象征性地描述一下问题:一组(或者一个)东西有且仅有两种选择,要么选这个,要么选那个,还有一堆的约束条件

图论问题,当然是建边跑图喽

给出模型:

模型一:两者(A,B)不能同时取

  那么选择了A就只能选择B’,选择了B就只能选择A’
  连边A→B’,B→A’

模型二:两者(A,B)不能同时不取

  那么选择了A’就只能选择B,选择了B’就只能选择A
  连边A’→B,B’→A

模型三:两者(A,B)要么都取,要么都不取

  那么选择了A,就只能选择B,选择了B就只能选择A,选择了A’就只能选择B’,选择了B’就只能选择A’
  连边A→B,B→A,A’→B’,B’→A’

模型四:两者(A,A’)必取A

  那么,那么,该怎么说呢?先说连边吧。
  连边A’→A

题目POJ3683

然后说一下这个题的意思:

如果某两个婚礼进行仪式的时间有重合

那么就存在了矛盾关系,通过这些关系连边

Tarjan缩点重新建图(这里建反向图),判断

将一个未着色点 x 上色同时,把与它矛盾的点 y 以及 y 的所有子孙节点上另外一种颜色

上色完成后,进行拓扑排序,选择一种颜色的点输出就是一组可行解

介绍一下实现:

int n,cnt,scc,ind,top;
int a[maxn],b[maxn],belong[maxn],op[maxn];
bool inq[maxn];int dfn[maxn],low[maxn],q[maxn],col[maxn];
int g[maxn],gd[maxn],d[maxn];
struct Edge{int t,next;}e[maxm],ed[maxm];

ind是自增的用来记录dfn,scc是连通分量个数

belong用于存每一个点属于哪一个连通分量

然后op用来记录同一组的互斥条件

col用来存颜色

d用来存点的度数,便于拓扑排序

下面给出完整实现,感觉这个题可以很好地拆成几个很好地模板(就比如说拓扑排序,重新建图,强连通缩点,哈哈)

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 const int maxn=2005;
  6 const int maxm=2000005;
  7 int n,cnt,scc,ind,top;
  8 int a[maxn],b[maxn],belong[maxn],op[maxn];
  9 bool inq[maxn];int dfn[maxn],low[maxn],q[maxn],col[maxn];
 10 int g[maxn],gd[maxn],d[maxn];
 11 struct Edge{int t,next;}e[maxm],ed[maxm];
 12 void addedge(int u,int v)
 13 {
 14     e[++cnt].t=v;e[cnt].next=g[u];
 15     g[u]=cnt;
 16 }
 17 void addedge2(int u,int v)
 18 {
 19     d[v]++;
 20     ed[++cnt].t=v;ed[cnt].next=gd[u];
 21     gd[u]=cnt;
 22 }
 23 inline int read()
 24 {
 25     int x=0,f=1;char ch=getchar();
 26     while(ch<0||ch>9) {if(ch==-)f=-1;ch=getchar();}
 27     while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
 28     return x*f;
 29 }
 30         //a[2i]-b[2i]前半程
 31         //a[2i-1]-b[2i-1]后半程 
 32 bool jud(int x,int y)
 33 {
 34     if(b[x]<=a[y]||a[x]>=b[y]) return 0;
 35     return 1;
 36 }
 37 void build()
 38 {
 39     for(int i=1;i<=n;i++)
 40         for(int j=i+1;j<=n;j++)
 41         {
 42             if(jud(2*i,2*j))
 43             {
 44                 addedge(2*i,2*j-1);
 45                 addedge(2*j,2*i-1);
 46             }
 47             if(jud(2*i,2*j-1))
 48             {
 49                 addedge(2*i,2*j);
 50                 addedge(2*j-1,2*i-1);
 51             }
 52             if(jud(2*i-1,2*j))
 53             {
 54                 addedge(2*i-1,2*j-1);
 55                 addedge(2*j,2*i);
 56             }
 57             if(jud(2*i-1,2*j-1))
 58             {
 59                 addedge(2*i-1,2*j);
 60                 addedge(2*j-1,2*i);
 61             }
 62         }
 63 }
 64 void tarjan(int x)
 65 {
 66     //cout<<x<<endl;
 67     dfn[x]=low[x]=++ind;
 68     q[++top]=x;inq[x]=1;
 69     for(int tmp=g[x];tmp;tmp=e[tmp].next)
 70         if(!dfn[e[tmp].t])
 71         {
 72             tarjan(e[tmp].t);
 73             low[x]=min(low[e[tmp].t],low[x]);
 74         }
 75         else if(inq[e[tmp].t])
 76             low[x]=min(dfn[e[tmp].t],low[x]);
 77         if(low[x]==dfn[x])
 78         {
 79             int temp=0;scc++;
 80             while(temp!=x)
 81             {
 82                 temp=q[top--];
 83                 inq[temp]=0;
 84                 belong[temp]=scc;
 85             }
 86         }
 87 }
 88 void rebuild()
 89 {
 90     cnt=0;
 91     for(int x=1;x<=2*n;x++)
 92         for(int tmp=g[x];tmp;tmp=e[tmp].next)
 93             if(belong[x]!=belong[e[tmp].t])
 94             {
 95                 //cout<<belong[e[tmp].t]<<" "<<belong[x]<<endl;
 96                 addedge2(belong[e[tmp].t],belong[x]);
 97             }
 98 
 99 }
100 void dfs(int x)
101 {
102     if(col[x]) return;
103     col[x]=-1;
104     for(int tmp=gd[x];tmp;tmp=ed[tmp].next)
105         dfs(ed[tmp].t);
106 }
107 void topsort()
108 {
109     for(int i=1;i<=scc;i++)
110         if(!d[i]) q[++top]=i;
111     while(top)
112     {
113         int temp=q[top--];
114         //cout<<temp<<endl;
115         if(col[temp]) continue;
116         col[temp]=1;dfs(op[temp]);
117         for(int tmp=gd[temp];tmp;tmp=ed[tmp].next)
118         {
119             d[ed[tmp].t]--;
120             if(!d[ed[tmp].t]) q[++top]=ed[tmp].t;
121         }
122     }
123 }
124 void print(int x)
125 {
126     printf("%.2d:",x/60);
127     printf("%.2d ",x%60);
128 }
129 int main()
130 {
131     n=read();
132     int x;
133     for(int i=1;i<=n;i++)
134     {
135         //a[2i]-b[2i]前半程
136         //a[2i-1]-b[2i-1]后半程 
137         a[2*i]=read();
138         a[2*i]=a[2*i]*60+read();
139         b[2*i-1]=read();
140         b[2*i-1]=b[2*i-1]*60+read();
141         x=read();
142         b[2*i]=a[2*i]+x;
143         a[2*i-1]=b[2*i-1]-x;
144     }
145     build();
146     for(int i=1;i<=2*n;i++)
147         if(!dfn[i]) tarjan(i);
148     for(int i=1;i<=n;i++)
149         if(belong[2*i]==belong[2*i-1])
150             {puts("NO");return 0;}
151     puts("YES");
152     rebuild();
153     for(int i=1;i<=n;i++)
154     {
155         op[belong[2*i]]=belong[2*i-1];
156         op[belong[2*i-1]]=belong[2*i];
157     }
158     topsort();
159     for(int i=1;i<=n;i++)
160         if(col[belong[2*i]]==1)
161             print(a[2*i]),print(b[2*i]),puts("");
162         else print(a[2*i-1]),print(b[2*i-1]),puts("");
163     return 0;
164 }

 

2-SAT问题的解决方案

标签:div   后半程   next   不能   选择   ||   include   name   新建   

原文地址:https://www.cnblogs.com/aininot260/p/9457908.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!