BZOJ4727: [POI2017]Turysta

77 篇文章 0 订阅
11 篇文章 0 订阅

第一次听说竞赛图这种东西..

竞赛图内一定存在哈密顿路径,将图缩点后,每个强连通分量内一定存在哈密顿回路,我们可以构造出哈密顿路径后构造哈密顿回路,两个强连通分量间,因为是竞赛图,又因为不在一个联通分量,所以其中一个里的每个点一定向另一个里的所有点都有边,然后可以在DAG上dp一下最长路径

详细的细节看这里吧我不想写了…(我也是对着这个膜的

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1e9
using namespace std;

inline void down(int &x,const int &y){if(x>y)x=y;}
const int maxn = 2100;

int n;
int mp[maxn][maxn],mp2[maxn][maxn];
int _in[maxn];

int cnt,id[maxn];
vector<int>V[maxn];

bool insta[maxn]; int T[maxn],tp;
int did,dfn[maxn],low[maxn];
void dfs(const int x)
{
    dfn[x]=low[x]=++did; 
    insta[T[++tp]=x]=true;
    for(int i=1;i<=n;i++) if(mp[x][i])
    {
        if(!dfn[i]) dfs(i),down(low[x],low[i]);
        else if(insta[i]) down(low[x],dfn[i]);
    }
    if(low[x]==dfn[x])
    {
        ++cnt;
        int la=0;
        while(la!=x)
        {
            insta[la=T[tp--]]=false;
            V[id[la]=cnt].push_back(la);
        }
    }
}
void tarjan()
{
    did=0; cnt=0;
    for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i);
}
int L[maxn],R[maxn];/*
bool use[maxn];
bool judge(int x,int tp)
{
    memset(use,false,sizeof use); use[x]=true;
    x=R[x];
    for(int i=2;i<=tp;i++)
    {
        if(use[x]||!x) return false;
        use[x]=true;
        x=R[x];
    }
    return true;
}*/
void make_circle()
{
    for(int i=1;i<=cnt;i++)
    {
        if(V[i].size()==1)
        {
            int x=V[i][0]; L[x]=R[x]=x;
            continue;
        }
        int head,tail;
        int x1=V[i][0],x2=V[i][1];
        if(mp[x2][x1]) swap(x1,x2);
        head=L[tail=R[x1]=x2]=x1;
        for(int j=2;j<V[i].size();j++)
        {
            int now=V[i][j];
            if(mp[now][head]) L[head]=now,R[now]=head,head=now;
            else if(mp[tail][now]) R[tail]=now,L[now]=tail,tail=now;
            else
            {
                int pos=head;
                while(mp[pos][now]&&mp[R[pos]][now]) pos=R[pos];
                int tr=R[pos];
                R[pos]=now,L[tr]=now;
                L[now]=pos,R[now]=tr;
            }
        }

        //int ti=1; //
        int pos=head; 
        while(!mp[pos][head]) pos=R[pos];//,ti++;
        int nex=R[pos];
        L[head]=pos,R[pos]=head;
        while(nex)
        {
            //ti++; //
            int now=nex; nex=R[nex];
            if(mp[now][R[pos]]) R[now]=R[pos],L[now]=pos,L[R[pos]]=now,R[pos]=now;
            else
            {
                int j=R[pos];
                while(j!=pos&&mp[j][now]&&mp[R[j]][now]) j=R[j];
                if(j!=pos)
                {
                    int tr=R[j];
                    L[now]=j,R[now]=tr;
                    L[tr]=now,R[j]=now;
                    //if(!judge(pos,ti)) { printf("%d %d\n",ti,2);return; }
                }
                else
                {
                    int tr=now;
                    while(1)
                    {
                        now=nex;nex=R[nex];
                        if(mp[now][pos]) {j=pos; break;}
                        for(j=R[pos];j!=pos&&mp[j][now];j=R[j]);
                        if(j!=pos) break;
                    }
                    int tl=L[j];
                    R[now]=j,L[j]=now;
                    R[tl]=tr,L[tr]=tl;
                    //if(!judge(pos,ti)) { printf("%d %d\n",ti,3);return; }
                }
            }
            pos=now;
        }
    }
}
int f[maxn],pre[maxn];
queue<int>q;
void dp()
{
    for(int i=1;i<=cnt;i++) if(!_in[i])
        q.push(i),f[i]=0;
    while(!q.empty())
    {
        const int x=q.front(); q.pop(); f[x]+=V[x].size();
        for(int i=1;i<=cnt;i++) if(mp2[x][i])
        {
            _in[i]--; if(!_in[i]) q.push(i);
            if(f[i]<f[x]) f[i]=f[x],pre[i]=x;
        }
    }
}
void Output()
{
    for(int i=1;i<=n;i++)
    {
        printf("%d ",f[id[i]]);
        printf("%d ",i);
        int now=R[i],ed=i;
        while(1)
        {
            if(now==ed)
            {
                if(!pre[id[now]]) break;
                ed=now=V[pre[id[now]]][0];
                printf("%d ",now); now=R[now];
            }
            else printf("%d ",now),now=R[now];
        }puts("");
    }
}

int main()
{
    scanf("%d",&n);
    for(int i=2;i<=n;i++) for(int j=1;j<i;j++)
    {
        int x; scanf("%d",&x);
        mp[j][i]=x; mp[i][j]=!x;
    }

    tarjan();
    make_circle();

    for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(id[i]!=id[j]&&!mp[i][j])
        if(!mp2[id[i]][id[j]]) mp2[id[i]][id[j]]=1,_in[id[j]]++;

    dp();
    Output();

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值