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("
");
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/ihopenot/p/6722735.html