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);
	}
}

posted @ 2018-02-28 20:37  Drenight  阅读(226)  评论(0编辑  收藏  举报