BZOJ4727: [POI2017]Turysta tarjan/竞赛图哈密顿
首先竞赛图保证是一定有哈密顿路径的,强连通的竞赛图一定有哈密顿回路
竞赛图求每个点的最长链,不重复经过点
思路就是对每个scc求出哈密顿回路,再按拓扑序n^2dp一下
哈密顿路径和哈密顿回路的构造法看的这篇文章Bfk_
#include<bits/stdc++.h> //#pragma comment(linker, "/STACK:1024000000,1024000000") #include<stdio.h> #include<algorithm> #include<queue> #include<string.h> #include<iostream> #include<math.h> #include<stack> #include<set> #include<map> #include<vector> #include<iomanip> #include<bitset> using namespace std; // #define ll long long #define ull unsigned long long #define pb push_back #define FOR(a) for(int i=1;i<=a;i++) #define sqr(a) (a)*(a) #define dis(a,b) sqrt(sqr(a.x-b.x)+sqr(a.y-b.y)) ll qp(ll a,ll b,ll mod){ ll t=1;while(b){if(b&1)t=t*a%mod;b>>=1;a=a*a%mod;}return t; } struct DOT{ll x;ll y;}; //inline void read(int &x){int k=0;char f=1;char c=getchar();for(;!isdigit(c);c=getchar())if(c=='-')f=-1;for(;isdigit(c);c=getchar())k=k*10+c-'0';x=k*f;} const int dx[4]={0,0,-1,1}; const int dy[4]={1,-1,0,0}; const int inf=0x3f3f3f3f; const ll Linf=0x3f3f3f3f3f3f3f3f; const ll mod=1e9+7;; const int maxn=2e3+43; int n,g[maxn][maxn]; int dfn[maxn],low[maxn],Time,S[maxn],ins[maxn],top,belong[maxn]; int cnt,root[maxn]; //scc数量,scc至高点 int tot,V[maxn];//scc.size int nxt[maxn]; int pre[maxn],to[maxn][maxn],du[maxn]; int q[maxn]; int dp[maxn]; void get(){ //scc内路径 //造哈密顿路径 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){ Time++;dfn[u]=low[u]=Time; 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]; belong[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[belong[x]]]); } int main(){ scanf("%d",&n); for(int i=1;i<n;i++)for(int j=1;j<=i;j++){ int x;scanf("%d",&x); 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] && belong[i]!=belong[j])to[belong[i]][belong[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++; //压入q栈从叶子dp 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[belong[i]]); print(i); } }