POJ 3683 Priest John's Busiest Day (2-SAT 输出路径)
来源:互联网 发布:skype for mac 下载 编辑:程序博客网 时间:2024/06/05 04:43
题目大意:
一个牧师要去主持婚礼,每对新人夫妻会给你两个时间和一个持续时间,分别为 from to 和value
你可以在from到from+value的时间段里给她们们举行婚礼,也可以在to-value到to的时间段里为她们举行婚礼,但是总是要选一个的。
然后现在给你n对夫妻的。问你能不能有一种可能的方案,如果有,按照输入的顺序,将每对夫妻举行婚礼的时间段输出出来。
第i对夫妻的两个时间段可以看成i和i+n这两个点,两个点中必选一个,典型的2-SAT问题。
关键是找到一组可行解。
总之大体思路即:通过矛盾关系建边,比如i和j有矛盾关系,也就是说这两个点不能同时选。所以建立i到j+n的边和j到i+n的边。然后tarjan跑强连通分量,对于每个点i,判断他和他所对应的点i+n是否在同一个联通分量里,如果在的话,说明存在矛盾,无解。否则,反向建图,拓扑排序,从入读为0的点开始选,如果没选过,那么直接选,然后对应着的新点肯定不选,然后从这个点把不选关系传递下去。
注意:
我们必须明确几个问题:
1. 由于2-SAT题目的特殊性,我们在建边的时候,总是建的对称的边,最后也肯定是一个对称的图,所以即使在经过缩点后,图依旧是对称的。
2. 缩点后正向建图也可以,只不过这时需要找出度为0的点,也不是不可以,只是你会发现你不容易删去跟此点有关的边,所以就很复杂。
3. 注意在构建新图的时候一定要注意重边,建出重边的话拓扑排序就会错。。
ac代码:
#include <iostream>#include <algorithm>#include <cstdio>#include <string.h>#include <queue>using namespace std;const int maxn = 2200;struct edge{ int from,to,v,next;}ed[40000000],a[2200];int head[maxn];int cnte,cnte2;void ae(int x,int y){ ed[++cnte].to = y; ed[cnte].next = head[x]; head[x]=cnte;}int ma[2200][2200];// 缩点之后的新图(反向图)int col[2200];//染成的颜色 1代表一个集合 -1代表i+n的那集合 0代表未访问过int fanxiang[2200];int dfn[maxn],low[maxn],vis[maxn],stak[maxn],belong[maxn],cntc,cnts,index;//strong connected component //cnt of stackvoid dfs(int u){ //tarjan里的dfs dfn[u]=low[u] = ++index; stak[cnts++]=u; vis[u]=1; for(int i = head[u];i!=-1;i=ed[i].next){ int v = ed[i].to; if(!dfn[v]){ dfs(v); low[u] = min(low[u],low[v]); } else if(vis[v]){ low[u] = min(low[u],dfn[v]); } } if(dfn[u]==low[u]){ cntc++;int v; do{ v = stak[--cnts]; vis[v] = 0; belong[v] = cntc; fanxiang[cntc] = v; }while(v!=u); }}int n,m;void tarjan(){ for(int i = 1;i <= 2*n;i++){ if(!dfn[i]){ dfs(i); } }}void f(int i ,int j){// 建边 (构建必选关系) int len1 = a[i].v,len2 = a[j].v; if( !(a[i].from+len1 <= a[j].from || a[j].from+len2 <= a[i].from) ){ ae(i,j+n);ae(j,i+n); } if( !(a[i].from+len1 <= a[j].to-len2 || a[j].to <= a[i].from) ){ ae(i,j);ae(j+n,i+n); } if( !(a[i].to <= a[j].from || a[j].from+len2 <= a[i].to-len1) ){ ae(i+n,j+n);ae(j,i); } if( !(a[i].to <= a[j].to-len2 || a[j].to<= a[i].to-len1) ){ ae(i+n,j);ae(j+n,i); }}int in[maxn];void dfscol(int u){//将不可选关系传递下去, for(int i = 1;i <= cntc;i++){ if(ma[u][i] == 1 && !col[i]){ col[i] = -1; dfscol(i); } }}int main(){ scanf("%d",&n); memset(head,-1,sizeof(head)); memset(ma,0,sizeof(ma)); int h1,m1,h2,m2,value; for(int i = 1;i <= n;i++){ scanf("%d:%d %d:%d %d",&h1,&m1,&h2,&m2,&value); a[i].from = h1*60+m1; a[i].to = h2*60+m2; a[i].v = value; } for(int i = 1;i <= n;i++){ for(int j = i+1;j <= n;j++) f(i,j); } tarjan(); int flag = 1; for(int i = 1;i <= n;i++){ if(belong[i] == belong[i+n]){ flag = 0;break; } } if(flag == 0){ puts("NO"); } else{ puts("YES"); queue<int> q; for(int i = 1;i <= 2*n;i++){//反向建新图 同时进行入度统计 for(int j = head[i];j!=-1;j=ed[j].next){ int to = ed[j].to,ii = belong[i],jj = belong[to]; if(ii != jj && ma[jj][ii]==0){//判重边 ma[jj][ii] = 1;in[ii]++; } } } for(int i = 1;i <= cntc;i++){//拓扑排序 取入读为0的点 if(in[i] == 0) q.push(i); } int top; while(!q.empty()){//依次选择当前没有被选过的点 染上色1 并将他对立的新点染成-1 top = q.front(); q.pop(); for(int i = 1;i <= cntc;i++){ if(ma[top][i] == 1){ in[i]--; if(in[i] == 0) q.push(i); } } if(col[top] == 0){ col[top] = 1; int to = fanxiang[top]; // 为了找到对立的新点 通过对立的原点来找 if(to > n) to -= n; else to += n; to = belong[to];col[to] = -1; dfscol(to); } } for(int i = 1;i <= n;i++){ // 对每个点(边) 判断他所处的新点的颜色,然后输出 if(col[belong[i]] == 1){ h1 = a[i].from/60;m1 = a[i].from % 60; printf("%02d:%02d ",h1,m1); a[i].from += a[i].v; h1 = a[i].from/60;m1 = a[i].from % 60; printf("%02d:%02d\n",h1,m1); } else{ a[i].to -= a[i].v; h1 = a[i].to/60;m1 = a[i].to % 60; printf("%02d:%02d ",h1,m1); a[i].to += a[i].v; h1 = a[i].to/60;m1 = a[i].to % 60; printf("%02d:%02d\n",h1,m1); } } } return 0;}
阅读全文
0 0
- poj 3683 Priest John's Busiest Day 2-SAT输出
- poj 3683 Priest John's Busiest Day(2-SAT 输出路径)
- POJ 3683 Priest John's Busiest Day (2-SAT 输出路径)
- POJ 3684 Priest John's Busiest Day 2-SAT+输出路径
- POJ 3683 Priest John's Busiest Day(2-SAT)
- poj 3683 Priest John's Busiest Day 2-sat
- poj 3683 Priest John's Busiest Day 2-SAT
- 2-sat->poj 3683 Priest John's Busiest Day
- poj - 3683 - Priest John's Busiest Day(2-SAT)
- 【POJ】3683 Priest John's Busiest Day 2-sat
- POJ 3683 Priest John's Busiest Day(2-sat)
- poj 3683 Priest John's Busiest Day 2-sat
- poj 3683 Priest John's Busiest Day 2-sat
- POJ 3683 - Priest John's Busiest Day(2-SAT)
- poj 3683 Priest John's Busiest Day(2-SAT)
- poj 3683 Priest John's Busiest Day 2-SAT
- POJ 3683 Priest John's Busiest Day(2-SAT)
- POJ - 3683 Priest John's Busiest Day(2-SAT)
- [Ubuntu/CentOS7]--源码安装git最新版
- RatingBar评分条组件的学习
- cookie与session会话知多少
- 织梦更新生成栏目和生成文档没反应的解决方法
- GPU图形绘制管线(二)
- POJ 3683 Priest John's Busiest Day (2-SAT 输出路径)
- unity PC和android不同平台读取xml文件比较
- C++类所占内存大小计算
- PoEdu_Python_Lesson006_调试方法、函数
- c语言之强制类型转换
- 详解UI设计配色中的黑与白
- Web目录全能扫描工具DirBuster
- Lock
- spring Resource和Autowired主要区别