• 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
  • 相关阅读:
    表的管理
    子查询
    sql语句
    基本sql语句与oracle函数
    Visual C# 2008+SQL Server 2005 数据库与网络开发6.1.1 报表服务概述
    Visual C# 2008+SQL Server 2005 数据库与网络开发 5.4 小结
    Visual C# 2008+SQL Server 2005 数据库与网络开发5.3.1 日期时间函数
    Visual C# 2008+SQL Server 2005 数据库与网络开发 5.3 函数
    Visual C# 2008+SQL Server 2005 数据库与网络开发第6章 数据报表
    Visual C# 2008+SQL Server 2005 数据库与网络开发5.2.2 GROUP BY
  • 原文地址:https://www.cnblogs.com/ihopenot/p/6722735.html
Copyright © 2020-2023  润新知