题意:
有一个牧师要给好几对新婚夫妇准备婚礼..
已知每对新婚夫妇的有空的时间以及婚礼持续时间..
问是否可以让每对新婚夫妇都得到该牧师的祝福~
如果可以就输出YES以及可行解 不可以就输出NO
输入:
一个n 表示有n对新婚夫妇
接下来n行每行a b c 表示在a~b这段时间有空..以及婚礼会持续 c..
P.S.时间只可以选在a开始或者b结束..
eg:08:00 09:00 30 可以在8:00~8:30举行婚礼或者8:30~9:00举行婚礼
思路:
2-sat 以在前一段时间举行婚礼或者后一段时间举行婚礼为2个可选方案
然后每对新婚夫妇婚礼时间冲突了就给和另外一个方案连线..
2-sat问题连边的要求就是这两个情况一定要同时发生..
然后根据建的图求强连通分量以及缩点..表示是否可以同时发生并方便后面拓扑排序..
总方案不成立的条件是一个强连通分量里有col[ i ] == col[ i+n ]
而找可行解的方案就是:
根据第一次建的图建一个反图..然后求逆拓扑排序..
建反图的原因是保持冲突的两个事件肯定会被染成不同的颜色..
求逆拓扑排序的原因也是为了对图染的色不会发生冲突..
输出可行解就是遍历一次逆拓扑排序时染成的颜色..
输出同一组颜色的解就是其中的一组可行解..
Tips:
※ 用双向链表..方便建反图..
※ 求强连通分量是把所有的点都遍历一遍..所以是2*n..
※ 建反图的时候是遍历所有的边..然后根据edge.from 和 edge.to 建图
※ 拓扑排序是对缩点后的有向无环图排序..找出一组可行解..
每次拓扑排序找到一个解的时候..就把和他冲突的另外一个解也染色了..
※ 连边的时候连的是必须发生的两件事..
※ 如果求连通分量染色的时候遇到冲突事件在一个分量中出现则不能有可行解
否则就把缩点后冲突事件记录起来..以便拓扑排序的时候染色..
※ 最后记录某一个颜色的可行解..
然后遍历一遍1~n 找出该时间是否属于该可行解..属于就输出..不属于就输出对立的解..
总结:
2-sat问题是
①. 把有冲突的分成n组
②. 每组2个..然后根据冲突关系把没冲突的连边
③. 用tarjan染色..
④. 把缩点后的图建反图..
⑤. 根据反图拓扑排序
⑥. 拓扑排序过程中给其中一组解染色..同时给冲突的解染色
⑦. 根据第⑥.步找出可行解并输出..
Code:
1 #include <stdio.h> 2 #include <cstring> 3 #include <fstream> 4 #include <algorithm> 5 using namespace std; 6 #define clr(x) memset(x, 0, sizeof(x)) 7 const int INF = 0x1f1f1f1f; 8 const int MAXN = 1010*2; 9 10 struct Time 11 { 12 int st; 13 int en; 14 int la; 15 }time[MAXN]; 16 17 struct Edge 18 { 19 int from; 20 int next; 21 int to; 22 }edge[3000010], edge2[3000010];///!!! 23 int head[MAXN], head2[MAXN]; 24 int tot, tot2; 25 26 void add(int s, int u) 27 { 28 edge[tot].from = s; 29 edge[tot].to = u; 30 edge[tot].next = head[s]; 31 head[s] = tot++; 32 } 33 34 void add2(int s, int u) 35 { 36 edge2[tot2].to = u; 37 edge2[tot2].next = head2[s]; 38 head2[s] = tot2++; 39 } 40 41 int low[MAXN], dfn[MAXN]; 42 int ins[MAXN], sta[MAXN], col[MAXN]; 43 int ti, top, cnt; 44 45 void tarjan(int u) 46 { 47 int i, j, k; 48 dfn[u] = low[u] = ++ti; 49 sta[++top] = u; 50 ins[u] = 1; 51 for(i = head[u]; i != -1; i = edge[i].next) { 52 k = edge[i].to; 53 if(!dfn[k]) { 54 tarjan(k); 55 low[u] = min(low[u], low[k]); 56 } else if(ins[k]) 57 low[u] = min(low[u], dfn[k]); 58 } 59 if(dfn[u] == low[u]) { 60 cnt++; 61 do 62 { 63 k = sta[top--]; 64 col[k] = cnt; 65 ins[k] = 0; 66 }while(k != u); 67 } 68 } 69 70 int n; 71 void solve_ta() 72 { 73 int i, j, k; 74 ti = cnt = top = 0; 75 clr(dfn); 76 for(i = 1; i <= 2*n; ++i) 77 if(!dfn[i]) 78 tarjan(i); 79 } 80 81 int ind[MAXN], res[MAXN]; 82 int q[MAXN]; 83 84 void make_G() 85 { 86 int i, j, k; 87 tot2 = 0; 88 memset(head2, 0xff, sizeof(head2)); 89 clr(ind); 90 for(i = 0; i < tot; ++i) {///!!!! 91 if(col[edge[i].from] != col[edge[i].to]) { 92 add2(col[edge[i].to], col[edge[i].from]); 93 ind[col[edge[i].from]]++; 94 } 95 } 96 } 97 98 int ccol[MAXN]; 99 int ans[MAXN], ct[MAXN]; 100 void toposort() 101 { 102 int front = 0, rear = 0; 103 int i, k; 104 make_G(); 105 top = 0; 106 clr(ccol); 107 for(i = 1; i <= cnt; i++)///!! 108 if(ind[i] == 0) 109 q[rear++] = i; 110 while(front < rear) { 111 int x = q[front++]; 112 if(ccol[x] == 0) { 113 ccol[x] = 1; 114 ccol[ct[x]] = -1; 115 } 116 for(i = head2[x]; i != -1;i = edge2[i].next) { 117 k = edge2[i].to; 118 ind[k]--; 119 if(ind[k] == 0) { 120 q[rear++] = k; 121 } 122 } 123 } 124 } 125 126 int main() 127 { 128 int i, j, k; 129 int sh, sm, eh, em, d;///!!! 130 bool flag; 131 // freopen("e:\\acm\\mess\\stdin-stdout\\in.txt", "r", stdin); 132 while(scanf("%d", &n) != EOF) 133 { 134 tot = 0; 135 memset(head, 0xff, sizeof(head)); 136 flag = false; 137 138 for(i = 1; i <= n; ++i) { 139 scanf("%d:%d %d:%d %d", &sh, &sm, &eh, &em, &d); 140 time[i].st = sh*60+sm; 141 time[i].en = eh*60+em; 142 time[i].la = d; 143 } 144 145 for(i = 1; i <= n; ++i) 146 for(j = 1; j <= n; ++j) 147 if(i != j) { 148 /* 149 if((time[i].st+time[i].la < time[j].st) || (time[i].st > time[j].st + time[j].la)) 150 add(i, j); 151 if((time[i].en-time[i].la > time[j].st+time[j].la) || (time[i].en < time[j].st)) 152 add(i+n, j); 153 if((time[i].st+time[i].la < time[j].en-time[j].la) || (time[i].st > time[j].en)) 154 add(i, j+n); 155 if((time[i].en-time[i].la > time[j].en) || (time[i].en < time[j].en-time[j].la)) 156 add(i+n, j+n); 157 */ 158 159 if(time[i].st < time[j].st+time[j].la && time[j].st < time[i].st+time[i].la ) 160 add(i, j+n); 161 if(time[i].st < time[j].en && time[j].en-time[j].la < time[i].st+time[i].la) 162 add(i, j); 163 if(time[i].en-time[i].la< time[j].st+time[j].la && time[j].st<time[i].en) 164 add(i+n, j+n); 165 if(time[i].en - time[i].la < time[j].en && time[j].en-time[j].la < time[i].en) 166 add(i+n, j); 167 } 168 169 solve_ta(); 170 for(i = 1; i <= n; ++i) { 171 if(col[i] == col[i+n]) { 172 flag = true; 173 break; 174 } 175 ct[col[i]] = col[i+n]; 176 ct[col[i+n]] = col[i]; 177 } 178 179 180 if(flag) puts("NO"); 181 else { 182 toposort(); 183 clr(ans); 184 185 for(i = 1; i <= 2*n; ++i) 186 if(ccol[col[i]] == 1) 187 ans[i] = 1; 188 puts("YES"); 189 for(i = 1; i <= n; ++i) { 190 if(ans[i]) printf("%02d:%02d %02d:%02d\n", time[i].st/60, time[i].st%60, (time[i].st+time[i].la)/60, (time[i].st+time[i].la)%60); 191 else printf("%02d:%02d %02d:%02d\n", (time[i].en-time[i].la)/60, (time[i].en-time[i].la)%60, time[i].en/60, time[i].en%60); 192 } 193 } 194 195 } 196 return 0; 197 }