zoukankan      html  css  js  c++  java
  • 【BZOJ4727】Turysta(POI2017)-构造+链表+SCC

    测试地址:Turysta
    题目大意:给定一张竞赛图,要求求出从每个点出发的,经过点数最多的一条简单路径,输出方案。
    做法:本题需要用到构造+链表+SCC。
    首先可以证明一张竞赛图必有一条哈密顿路径(反证法),又可以证明一张强连通的竞赛图必有一条哈密顿回路(这个暂时不知道怎么证,不过看了下面的构造方法差不多也能明白)。我们先来找出原图的哈密顿路径。
    竞赛图的任意导出子图一定都是竞赛图,所以我们可以递推进行:假设我们已经求出包含1i的哈密顿路径,那么对于点i+1
    如果它指向前面求出的哈密顿路径的头,或者被前面求出的哈密顿路径的尾指向,就直接接上去。
    否则,我们至少知道点i+1被前面求出的哈密顿路径的头指向,并指向前面求出的哈密顿路径的尾。因此在这条路径中一定存在相邻的两个点,满足前面的点指向i+1,后面的点被i+1指向,那么只要把i+1接在两点之间即可。这样的递推用链表维护是O(n2)的。
    求出了哈密顿路径,我们能断言:这张图的任意强连通分量必定是这条路径上的一个连续段,并且两个不同强连通分量之间的边的联系,只有可能是从路径中靠前的连向路径中靠后的。换句人话来说,就是对竞赛图SCC缩点后得到的一定是一条链。
    前面我们说了,一个强连通竞赛图中必然含有哈密顿回路,那么现在问题就变成,如何求出这样的哈密顿回路,求出之后我们就可以很方便地构造出题目中所求的最佳路径了:首先按当前强连通分量的哈密顿回路走,然后贪心走到下一个强连通分量,再按哈密顿回路走……
    下面我们给出有哈密顿路的基础上,求哈密顿回路的算法。我们假设已经求出哈密顿路上前i个点的哈密顿回路,而后面接着一条链直到第j个点,那么:
    如果环中存在一个位置使得它被j指向,而它在环上的前一个点指向从环中接出的那条链的头,那么就可以把这条链接到环中。
    否则,跳过当前点,考虑j+1
    于是我们就解决了这一题,时间复杂度为O(n2)
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    int n,pre[2010]={0},nxt[2010]={0},head=1,tail=1;
    int low[2010],dfn[2010],tim=0,belong[2010],totscc=0;
    int st[2010],top=0;
    int looppre[2010],loopnxt[2010],nxtscc[2010];
    bool g[2010][2010]={0},vis[2010]={0},inst[2010]={0};
    
    void insert(int x,int y)
    {
        pre[nxt[x]]=y;
        nxt[y]=nxt[x];
        nxt[x]=y;
        pre[y]=x;
    }
    
    void calc_path()
    {
        for(int i=2;i<=n;i++)
        {
            if (g[i][head])
            {
                nxt[i]=head;
                pre[head]=i;
                head=i;
                continue;
            }
            if (g[tail][i])
            {
                nxt[tail]=i;
                pre[i]=tail;
                tail=i;
                continue;
            }
            int x=head;
            while(!g[i][nxt[x]]) x=nxt[x];
            insert(x,i);
        }
    }
    
    void tarjan(int v)
    {
        vis[v]=1;
        dfn[v]=low[v]=++tim;
        st[++top]=v;
        inst[v]=1;
        int now=top;
        for(int i=1;i<=n;i++)
            if (g[v][i])
            {
                if (!vis[i])
                {
                    tarjan(i);
                    low[v]=min(low[v],low[i]);
                }
                else if (inst[i]) low[v]=min(low[v],dfn[i]);
            }
        if (low[v]>=dfn[v])
        {
            ++totscc;
            for(int i=now;i<=top;i++)
            {
                belong[st[i]]=totscc;
                inst[st[i]]=0;
            }
            top=now-1;
        }
    }
    
    void calc_loop(int &v,int c)
    {
        int x=v;
        if (!nxt[x]||belong[nxt[x]]!=c)
        {
            looppre[x]=loopnxt[x]=x;
            nxtscc[x]=nxt[x];
            v=nxt[x];
            return;
        }
    
        while(x&&belong[x]==c)
        {
            looppre[x]=pre[x];
            if (g[x][v])
            {
                loopnxt[x]=v;
                looppre[v]=x;
                break;
            }
            loopnxt[x]=nxt[x];
            x=nxt[x];
        }
    
        x=nxt[x];
        int now=x;
        while(x&&belong[x]==c)
        {
            int p=v;
            bool flag=0;
            do
            {
                if (g[p][now]&&g[x][loopnxt[p]])
                {
                    loopnxt[x]=loopnxt[p];
                    looppre[loopnxt[p]]=x;
                    looppre[now]=p;
                    loopnxt[p]=now;
                    flag=1;
                    break;
                }
                p=loopnxt[p];
            }while(p!=v);
            if (flag) now=nxt[x];
            else loopnxt[x]=nxt[x],looppre[x]=pre[x];
            x=nxt[x];
        }
        int tmp=v;
        while(tmp&&belong[tmp]==c)
            nxtscc[tmp]=x,tmp=nxt[tmp];
        v=x;
    }
    
    void calc_ans(int i,bool type)
    {
        int x=i,cnt=0;
        while(x)
        {
            int v=x;
            do
            {
                if (type) printf("%d ",v);
                else cnt++;
                v=loopnxt[v];
            }while(v!=x);
            x=nxtscc[x];
        }
        if (!type) printf("%d ",cnt);
        else printf("
    ");
    }
    
    void work()
    {
        int x=head;
        while(x) calc_loop(x,belong[x]);
        for(int i=1;i<=n;i++)
        {
            calc_ans(i,0);
            calc_ans(i,1);
        }
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n-1;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;
            }
    
        calc_path();
        tarjan(head);
        work();
    
        return 0; 
    }
  • 相关阅读:
    Eclipse安装Hadoop插件
    (转)Ubuntu14.0.4中hadoop2.4.0伪分布模式配置
    Hadoop--DataNode无法启动
    启动与关闭hadoop
    hadoop中执行命令时发生错误
    strings命令
    Deriving data from ElasticSearch Engine
    elasticsearch data importing
    reading words in your computer and changing to female voice, linux festival text2wave saving wav files
    DDNS client on a Linux machine
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793296.html
Copyright © 2011-2022 走看看