Pentium.Labs

System全家桶:https://zhuanlan.zhihu.com/c_1238468913098731520

导航

poj 3683 2-SAT入门

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

 

  1 #include "cstdio"
  2 #include "vector"
  3 #include "stack"
  4 #include "cstring"
  5 using namespace std;
  6 #define maxn 2010
  7 
  8 int n,N,dfs_clock,scc_cnt,v,tt=0;
  9 char st[10];
 10 int S[maxn],T[maxn],D[maxn],pre[maxn],sccno[maxn],lowlink[maxn],id[maxn],cfl[maxn],color[maxn],done[maxn];
 11 int G[maxn][maxn],G2[maxn][maxn];
 12 stack<int> St;
 13 
 14 void tarjan(int u)
 15 {
 16     pre[u]=lowlink[u]=++dfs_clock;
 17     St.push(u);
 18     for (int i=1;i<=G[u][0];i++)
 19     {
 20         int v=G[u][i];
 21         if (!pre[v])
 22         {
 23             tarjan(v);
 24             lowlink[u]=min(lowlink[u],lowlink[v]);
 25         }
 26         else if (!sccno[v])
 27         {
 28             lowlink[u]=min(lowlink[u],pre[v]);
 29         }
 30     }
 31     if (lowlink[u]==pre[u])
 32     {
 33         scc_cnt++;
 34         for (;;)
 35         {
 36             int x=St.top();
 37             St.pop();
 38             sccno[x]=scc_cnt;
 39             if (x==u) break;
 40         }
 41     }
 42 }
 43 
 44 void find_scc(int n)
 45 {
 46     dfs_clock=scc_cnt=0;
 47     memset(sccno,0,sizeof(sccno));
 48     memset(pre,0,sizeof(pre));
 49     for (int i=1;i<=n;i++)
 50         if (!pre[i])
 51             tarjan(i);
 52 }
 53 
 54 void add_edge(int x,int y)
 55 {
 56     G[x][0]++;
 57     G[x][G[x][0]]=y;
 58 }
 59 
 60 void _add_edge(int x,int y)
 61 {
 62     G2[x][0]++;
 63     G2[x][G2[x][0]]=y;
 64 }
 65 
 66 void solve()
 67 {
 68     //1->N:x[i]        N+1->2N:not x[i]
 69     v=N*2;
 70     for (int i=1;i<=N;i++)
 71     {
 72         for (int j=i+1;j<=N;j++)
 73         {
 74             if (min(S[i]+D[i],S[j]+D[j])>max(S[i],S[j]))    //事件i和j不能同时满足,连边
 75             {
 76                 add_edge(i,N+j);
 77                 add_edge(j,N+i);
 78             }
 79             if (min(S[i]+D[i],T[j])>max(S[i],T[j]-D[j]))
 80             {
 81                 add_edge(i,j);
 82                 add_edge(N+j,N+i);
 83             }
 84             if (min(T[i],S[j]+D[j])>max(T[i]-D[i],S[j]))
 85             {
 86                 add_edge(N+i,N+j);
 87                 add_edge(j,i);
 88             }
 89             if (min(T[i],T[j])>max(T[i]-D[i],T[j]-D[j]))
 90             {
 91                 add_edge(N+i,j);
 92                 add_edge(N+j,i);
 93             }
 94         }
 95     }
 96 }
 97 
 98 void topsort(int x)
 99 {
100     int j;
101     id[x] = -1;
102     done[++tt]=x;
103     for(int k=1;k<=G2[x][0];k++)
104     {
105         j = G2[x][k];
106         id[j]--;
107         if( id[j] == 0 ) topsort( j );
108     }
109 }
110 
111 void dfs( int i )
112 {
113     int j;
114     color[i] = 2;
115     for(int k=1;k<=G[i][0];k++)
116     {
117         j = G2[i][k];
118         if( color[j] == 0 ) dfs( j );
119     }
120 }
121 
122 void print( int aa, int bb )
123 {
124     if( aa / 60 < 10 ) printf( "0" );
125     printf( "%d:", aa / 60 );
126     if( aa % 60 < 10 ) printf( "0" );
127     printf( "%d ", aa % 60 );
128     if( bb / 60 < 10 ) printf( "0" );
129     printf( "%d:", bb / 60 );
130     if( bb % 60 < 10 ) printf( "0" );
131     printf( "%d\n", bb % 60 );
132 }
133 
134 int main()
135 {
136     scanf("%d",&N);
137     for( int i = 1; i <= N; i++ )       //时间统一转化成分钟存储
138     {
139         scanf( "%s", st );
140         S[i] = ( st[0]-48 )*600 + ( st[1]-48 )*60;
141         S[i] += ( st[3]-48 )*10 + st[4]-48;
142         scanf( "%s", st );
143         T[i] = ( st[0]-48 )*600 + ( st[1]-48 )*60;
144         T[i] += ( st[3]-48 )*10 + st[4]-48;
145         scanf( "%d", &D[i] );
146     }
147 
148     solve();
149     find_scc(2*N);
150 
151     for (int i=1;i<=N;i++)
152     {
153         if (sccno[i]==sccno[N+i])
154         {
155             printf("NO\n");
156             return 0;
157         }
158     }
159 
160     //printf("YES\n");
161     for (int i=1;i<=2*N;i++)        //强连通分量缩点并对块反向连边
162     {
163         for (int j=1;j<=G[i][0];j++)
164         {
165             int tm=G[i][j];
166             if (sccno[i]!=sccno[tm])
167             {
168                 _add_edge(sccno[tm],sccno[i]);
169                 id[sccno[i]]++;
170             }
171         }
172     }
173     for (int i=1;i<=scc_cnt;i++)    //对缩点之后的块拓扑排序,
174         if (id[i]==0)
175             topsort(i);
176 
177     for( int i = 1; i <= N; i++ )
178     {
179         cfl[ sccno[i] ] = sccno[i+N];
180         cfl[ sccno[i+N] ] = sccno[i];
181     }
182     
183     for( int ii = 1; ii <= scc_cnt; ii++ )      //按拓扑序对块染色,求方案
184     {
185         int i = done[ii];           //done[]:拓扑序列
186         if( color[i] != 0 ) continue;
187         color[i] = 1;               //color[]=1:选刚开始的时段,S~S+D
188         dfs( cfl[i] );              //color[]=2:选结束的时段,T-D~T
189     }
190     printf("YES\n");
191     for( int i = 1; i <= N; i++ )
192         if( color[ sccno[i] ] == 1 )
193             print( S[i], S[i]+D[i] );
194         else
195             print( T[i]-D[i], T[i] );
196 
197     return 0;
198 }
199 
200 
201 
202 
203 //一直觉得ICPC不应该是种功利性的东西,那样就彻底变味了,也没意义了
204 //今年要干就好好干吧,也许明年就不打了
205 //没办法,有些事太复杂
206 //反正个人认为几个真心的朋友比所谓的成绩重要得多得多。
207 //208 //就这样吧

 

posted on 2014-10-29 15:43  Pentium.Labs  阅读(195)  评论(0编辑  收藏  举报



Pentium.Lab Since 1998