bzoj4727 [POI2017]Turysta(竞赛图构造哈密顿回路)
2018-01-23 23:41
323 查看
bzoj4727 [POI2017]Turysta
原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=4727题意:
给出一个n个点的有向图,任意两个点之间有且仅一条有向边。对于每个点v,求出从v出发的一条经过点数最多,
且没有重复经过同一个点两次以上的简单路径。
输入第一行包含一个正整数n(2<=n<=2000),表示点数。接下来n-1行,其中的第i行有i-1个数,如果第j个数是1,那么
表示有向边j->i+1,如果是0,那么表示有向边j<-i+1。
数据范围
2<=n<=2000
题解:
原图给出来是一个竞赛图。
定理:
竞赛图一定存在哈密顿路径
竞赛图存在哈密顿回路 充要条件是强连通。
那么每个强连通分量里的点每个点都可以走完所有的点。
那么这道题就是竞赛图构造哈密顿回路。
然后拓扑序DP。
关于竞赛图如何构造(以及上述两个定理的证明):
在竞赛图中构造哈密顿路径:
假设我们已经构造出了前i个点的哈密顿路径(最初为1),那么加入i+1个点时,会有三种情况:
1、指向首。
2、被尾指向。
这两种之间就加在首位了。
3、找到中间第一个被i+1指向的点,它前一个点与i+1与它重新连接。
已知强连通竞赛图中的哈密顿路径,如何构造哈密顿回路:
首先找到最近的那个指向首的节点i,形成一个环(因为强连通所以一定存在),然后考虑把环扩大,到i+1节点。
1、指向首,就直接扩大即可。
2、指向其中的某个点,走如图的路径形成新环。
3、没有指向环,考虑下一个点。
于是就完成了构造及证明。
代码:
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> using namespace std; const int N=2005; int n,x,g ,to ,dp ,low ,dfn ,inc=0,S ,top=0,pl ,cnt=0,q ,du ,pre ,root ,tot=0,V ,nxt ; bool ins ; inline int read() { int ret=0,w=1; char ch=getchar(); while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); if(ch=='-'){w=-1; ch=getchar();} while(ch>='0'&&ch<='9') {ret=(ret<<1)+(ret<<3)+ch-'0'; ch=getchar();} return ret*w; } void get() { int head=V[1]; int tail=V[1]; if(tot==1) {nxt[tail]=tail; return;} for(int j=2;j<=tot;j++) { int i=V[j]; if(g[i][head]){nxt[i]=head; head=i; continue;} else if(g[tail][i]){nxt[tail]=i; tail=i; continue;} int x,y; for(x=nxt[head],y=head;x&&!g[i][x];y=x,x=nxt[x]); nxt[y]=i; nxt[i]=x; } tail=head; head=0; for(int i=nxt[tail];i;i=nxt[i]) { if(head) { for(int p1=head,p2=tail;;p2=p1,p1=nxt[p1]) { if(g[i][p1]) { nxt[p2]=nxt[tail]; if(p2!=tail) nxt[tail]=head; tail=i; head=p1; break; } if(p1==tail) break; } } else if(g[i][tail]){head=tail;tail=i;} } nxt[tail]=head; } void dfs(int u) { inc++; dfn[u]=low[u]=inc; ins[u]=1; S[++top]=u; for(int v=1;v<=n;v++) if(g[u][v]) { if(!dfn[v]) {dfs(v); low[u]=min(low[u],low[v]);} else if(ins[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]) { cnt++; root[cnt]=u; tot=0; while(1) { dp[cnt]++; V[++tot]=S[top]; pl[S[top]]=cnt; ins[S[top]]=0; top--; if(S[top+1]==u) break; } get(); } } void print(int x) { if(!x){printf("\n");return;} printf("%d ",x); for(int i=nxt[x];i!=x;i=nxt[i]) printf("%d ",i); print(root[pre[pl[x]]]); } int main() { scanf("%d",&n); for(int i=1;i<n;i++) for(int j=1;j<=i;j++) { x=read(); if(x) g[j][i+1]=1; else g[i+1][j]=1; } for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(g[i][j]&&pl[i]!=pl[j]) to[pl[i]][pl[j]]=1; for(int i=1;i<=cnt;i++) for(int j=1;j<=cnt;j++) if(i!=j&&to[j][i]) du[i]++; int lf=1,rg=0; top=0; for(int i=1;i<=cnt;i++) if(du[i]==0) S[++rg]=i; while(lf<=rg) { int x=q[++top]=S[lf]; lf++; for(int y=1;y<=cnt;y++) { if(!to[x][y]||y==x) continue; du[y]--; if(du[y]==0) S[++rg]=y; } } for(int i=top;i>=1;i--) { int x=q[i]; int det=0; for(int y=1;y<=cnt;y++) { if(!to[x][y]||x==y) continue; if(det<dp[y]){det=dp[y]; pre[x]=y;} } dp[x]+=det; } for(int i=1;i<=n;i++) {printf("%d ",dp[pl[i]]); print(i);} return 0; }
相关文章推荐
- BZOJ4727 [POI2017]Turysta 【竞赛图哈密顿路径/回路】
- BZOJ4727: [POI2017]Turysta
- 【BZOJ4727】【POI2017】Turysta
- bzoj千题计划232:bzoj4727: [POI2017]Turysta
- BZOJ.4727.[POI2017]Turysta(哈密顿路径/回路 竞赛图)
- bzoj 4727 [POI2017]Turysta 竞赛图
- BZOJ4727 [POI2017]Turysta
- BZOJ4727: [POI2017]Turysta
- BZOJ4727: [POI2017]Turysta tarjan/竞赛图哈密顿
- bzoj 4727: [POI2017]Turysta 图论
- BZOJ 4727: [POI2017]Turysta
- 4727: [POI2017]Turysta
- hdu 3414----竞赛图中找寻是否存在哈密顿回路
- POJ 1776 Task Sequences(竞赛图构造哈密顿通路)
- 竞赛图如何构造三元环
- HDU 4337 King Arthur's Knights [哈密顿回路构造]
- hduTour Route【竞赛图的哈密顿回路】
- HDU3414 Tour Route(竞赛图寻找哈密顿回路)
- ZOJ 3332 Strange Country II (竞赛图构造哈密顿通路)
- HDU 3414 Tour Route(竞赛图的哈密顿回路)