[bzoj 4727--POI2017]Turysta

給出一個n個點的有向圖,任意兩個點之間有且僅一條有向邊。
對於每個點v,求出從v出發的一條經過點數最多,且沒有重複經過同一個點兩次及兩次以上的簡單路徑。

這道題首先我們要知道一個性質,一個強連通的競賽圖存在哈密頓迴路。
那麼就先tarjan一下,對每個強連通的競賽子圖處理出哈密頓迴路。然後再拓撲一下之後dp就可以了。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
vector<int>p[2010],to[2010];
queue<int>q;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
inline void write(int x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
struct node
{
    int x,y,next;
}a[2000010];int len,last[2010];
inline void ins(int x,int y)
{
    len++;
    a[len].x=x,a[len].y=y;
    a[len].next=last[x],last[x]=len;
}
int id,low[2010],dfn[2010];
int top,sta[2010];
int cnt,belong[2010],rt[2010];
bool v[2010],pd[2010][2010];
inline void dfs(int x)
{
    low[x]=dfn[x]=++id;sta[++top]=x,v[x]=true;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(!dfn[y])dfs(y),low[x]=min(low[x],low[y]);
        else if(v[y]==true)low[x]=min(low[x],dfn[y]);
    }
    if(low[x]==dfn[x])
    {
        cnt++;rt[cnt]=x;int i;
        do{
            i=sta[top--];
            v[i]=false;
            belong[i]=cnt;p[cnt].push_back(i);
        }while(i!=x);
    }
}
int ru[2010],nex[2010],pre[2010],chu[2010],f[2010];
inline void solve(int x)
{
    if(x==0)return ;
    int y=x;
    do{write(y),putchar(' ');y=nex[y];}while(y!=x);
    solve(rt[pre[belong[x]]]);
}
int main()
{
    //freopen("4727.in","r",stdin);
    //freopen("4727.out","w",stdout);
    int n=read();
    for(int i=2;i<=n;i++)
    {
        for(int j=1;j<i;j++)
        {
            int id=read();
            if(id==0)ins(i,j),pd[i][j]=true;
            else ins(j,i),pd[j][i]=true;
        }
    }
    for(int i=1;i<=n;i++)if(dfn[i]==0)dfs(i);
    for(int i=1;i<=cnt;i++)
    {
        int head=p[i][0],tail=p[i][0];
        for(int j=1;j<p[i].size();j++)
        {
            if(pd[p[i][j]][head])chu[p[i][j]]=head,head=p[i][j];
            else if(pd[tail][p[i][j]])chu[tail]=p[i][j],tail=p[i][j];
            else
            {
                int d=head;
                while(1)
                {
                    if(pd[d][p[i][j]]==true && pd[p[i][j]][chu[d]]==true){chu[p[i][j]]=chu[d],chu[d]=p[i][j];break;}
                    d=chu[d];
                }
            }
        }if(p[i].size()==1){nex[tail]=head;continue;}
        int u=chu[head],id;chu[tail]=0;
        while(u!=0){if(pd[u][head]==true)id=u;u=chu[u];}
        u=head;
        while(u!=id){nex[u]=chu[u],u=chu[u];}nex[id]=head;
        if(id==tail)continue;
        int d=chu[id],lt=d;
        while(d!=0)
        {
            int o=nex[head],la=head;bool bk=false;
            while(o!=head)
            {
                if(pd[d][o]==true)
                {
                    nex[la]=lt;bk=true;
                    int j=lt;
                    while(j!=d)nex[j]=chu[j],j=chu[j];
                    nex[d]=o;
                    break;
                }
                o=nex[o];la=nex[la];
            }
            d=chu[d];if(bk==true)lt=d;
        }
    }
    for(int i=1;i<=len;i++)
    {
        int bx=belong[a[i].x],by=belong[a[i].y];
        if(bx!=by)ru[bx]++,to[by].push_back(bx);
    }
    for(int i=1;i<=cnt;i++)if(ru[i]==0)q.push(i),f[i]=p[i].size();
    while(q.empty()!=true)
    {
        int x=q.front();q.pop();
        for(int i=0;i<to[x].size();i++)
        {
            int y=to[x][i],ul=f[x]+p[y].size();
            if(f[y]<ul)f[y]=ul,pre[y]=x;
            ru[y]--;if(ru[y]==0)q.push(y);
        }
    }
    for(int i=1;i<=n;i++){write(f[belong[i]]),putchar(' ');solve(i),puts("");}
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章