Bzoj4727--Poi2017Turysta
题意 :
给你一个竞赛图,问你从每个点出发的最长路径,并且输出最长路径。要求每个点只能经过一次。
数据范围 :n<=2000
--------------------------------------------------此后一千里---------------------------------------------------------
有向有环一般要缩环。所以我们可以考虑用强连通分量加dp去做。
那么可以先跑出所有强连通分量,再dp。但是有每个点只能经过一次的限定,就很蛋疼。
然后有一个结论,竞赛图的强连通分量必然存在一条哈密顿回路。
证明方法,可以先跑出一个环,把整个强连通分量化成基环外向树的形态,然后对于每个向外的链我们都可以并入环中。
具体细节可以参见代码。。
ps:输出路径贼蛋疼,写了半天。。
代码 :
//That's right ,I am killer . #include<bits/stdc++.h> #define LL long long #define eps 1e-9 #define INF 0x3f3f3f3f using namespace std; #define int int inline int Max(int a,int b) {return a>b?a:b;} inline int Min(int a,int b) {return a<b?a:b;} inline int Sqr(int a) {return a*a;} inline int Abs(int a) {return a>0?a:-a;} #undef int #define MAXN 2005 int n;bool mp[MAXN][MAXN]; struct Edge{ int to,next; }e[MAXN*MAXN];int head[MAXN],cnt; inline void Insert(int a,int b) { e[++cnt].next=head[a];head[a]=cnt;e[cnt].to=b; } bool inq[MAXN];int dfn[MAXN],low[MAXN],tim,stk[MAXN],top,scc,bln[MAXN],sz[MAXN]; int hs[MAXN][MAXN],go[MAXN],sk[MAXN],tp,bk[MAXN],in[MAXN];bool vis[MAXN]; bool Extend(int v,int fr,int p,int k); void Check(int v,int sc); bool Extend(int v,int fr,int p,int k) { int t=fr;bool ret; while(go[fr]!=t) { if(mp[v][go[fr]]) { t=go[fr];go[fr]=v;go[v]=t; ret=1;sk[++tp]=v;break; } fr=go[fr]; } if(!ret) { for(int i=head[v];i;i=e[i].next) { if(bln[e[i].to]==bln[fr]&&!vis[e[i].to]) if(Extend(e[i].to,t,1,v)) {sk[++tp]=v;go[k]=v,go[v]=e[i].to;break;} } } if(p) return ret; while(tp&&!vis[sk[tp]]) { vis[sk[tp]]=1; Check(sk[tp],bln[v]); tp--; } } void Check(int v,int sc) { for(int i=head[v];i;i=e[i].next) if(bln[e[i].to]==sc&&!vis[e[i].to]) Extend(e[i].to,v,0,v); } void Work(int sc) { if(sz[sc]==1) {go[hs[sc][1]]=hs[sc][1];return;} tp=0;int st=hs[sc][1];bool flag=0; queue<int> q;q.push(st);vis[st]=1; while(!q.empty()) { if(flag) break; int now=q.front();q.pop(); for(int i=head[now];i;i=e[i].next) { if(!vis[e[i].to]&&bln[e[i].to]==sc) { bk[e[i].to]=now; q.push(e[i].to);vis[e[i].to]=1; } if(e[i].to==st) { memset(vis,0,sizeof(vis)); go[now]=st;sk[++tp]=now;vis[now]=1; while(now!=st) { go[bk[now]]=now; now=bk[now]; sk[++tp]=now; vis[now]=1; } flag=1;break; } } } while(tp) { Check(sk[tp],sc); tp--; } } void Tarjan(int v) { inq[v]=1;stk[++top]=v; dfn[v]=low[v]=++tim; for(int i=head[v];i;i=e[i].next) { if(!dfn[e[i].to]) { Tarjan(e[i].to); low[v]=Min(low[v],low[e[i].to]); } else if(inq[e[i].to]) low[v]=Min(low[v],dfn[e[i].to]); } if(dfn[v]==low[v]) { scc++;int now; while(inq[v]) { now=stk[top--]; bln[now]=scc; inq[now]=0; sz[scc]++; hs[scc][++hs[scc][0]]=now; } Work(scc); } } void Rebuild() { memset(mp,0,sizeof(mp)); for(int i=1;i<=n;i++) for(int j=head[i];j;j=e[j].next) mp[bln[i]][bln[e[j].to]]=1; memset(head,0,sizeof(head));cnt=0; for(int i=1;i<=scc;i++) for(int j=i+1;j<=scc;j++) { if(mp[i][j]) {Insert(j,i);in[i]++;} if(mp[j][i]) {Insert(i,j);in[j]++;} } } int dp[MAXN],dbk[MAXN]; void Topo(int v) { dp[v]+=sz[v];vis[v]=1; for(int i=head[v];i;i=e[i].next) { if(dp[v]>dp[e[i].to]) dp[e[i].to]=dp[v],dbk[e[i].to]=v; if(!(--in[e[i].to])&&!vis[e[i].to]) Topo(e[i].to); } } int bat[100]; void Out(int d) { bat[0]=0; while(d) {bat[++bat[0]]=d%10;d/=10;} while(bat[0]) { putchar(bat[bat[0]]+'0'); bat[0]--; } putchar(' '); } void Cout(int v,int q) { int t=hs[v][1];v=t;if(bln[q]==bln[v]) v=q,t=q; Out(t);v=go[v]; while(v!=t) { Out(v); v=go[v]; } } int main() { scanf("%d",&n); for(int p,i=2;i<=n;i++) for(int j=1;j<i;j++) { scanf("%d",&p); if(p) {Insert(j,i);mp[j][i]=1;} else {Insert(i,j);mp[i][j]=1;} } for(int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i); Rebuild(); memset(vis,0,sizeof(vis)); for(int i=1;i<=scc;i++) if(!in[i]&&!vis[i]) Topo(i); for(int i=1;i<=n;i++) { Out(dp[bln[i]]); int t=bln[i]; while(t) {Cout(t,i);t=dbk[t];} printf("\n"); } return 0; }