zoukankan      html  css  js  c++  java
  • 【刷题】【环套树】旅行

    noip2018

    小 Y 的旅行方案是这样的:

    任意选定一个城市作为起点,然后从起点开始,

    每次可以选择一条与当前城市相连的道路,走向一个没有去过的城市或者沿着第一次访问该 城市时经过的道路后退到上一个城市

    当小 Y 回到起点时,她可以选择结束这次旅行或 继续旅行。

    需要注意的是,小 Y 要求在旅行方案中,每个城市都被访问到。

    为了让自己的旅行更有意义,小 Y 决定在每到达一个新的城市(包括起点)时,将 它的编号记录下来。她知道这样会形成一个长度为 nn 的序列。

    她希望这个序列的字典序 最小

    对于 100% 的数据和所有样例, 1n5000

     且 m = n − 1 或 m = n 。

    题解:

    因为只能回到上一个,所以当形状为树的时候,易知只能走dfs序

    当形状为树上套一个环的时候,走法多样,无法简单便利,

    所以我们考虑删除一条环上的边,用topo

    很多预处理,很多细节,具体看代码

    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<queue>
    using namespace std;
    int n,m;
    const int N=5003;
    int head[N],tot;
    struct node
    {
        int v,nx;
    }e[N<<1];
    void add(int u,int v)
    {
        e[++tot].v =v,e[tot].nx =head[u],head[u]=tot;
        e[++tot].v =u,e[tot].nx =head[v],head[v]=tot;
    }
    
    int in[N];
    int son[N<<1],cnt,st[N],ed[N];
    void topo()
    {
        queue <int> q;
        for(int i=1;i<=n;i++)
            if(in[i]==1) q.push(i);
        while(!q.empty() )
        {
            int u=q.front() ;q.pop() ;
            for(int i=st[u];i<=ed[u];i++)
                if(in[son[i]]>1)
                {
                    in[son[i]]--;
                    if(in[son[i]]==1) q.push(son[i]); 
                }
        }    
    }
    bool broken[N][N],change,fail; 
    int ans[N],pos;
    void dfs(int rt,int f)
    {
        if(fail) return ;
        
        ++pos;
        if(change || !ans[pos] || ans[pos]>rt ) 
            ans[pos]=rt,change=true;
        if( ans[pos]<rt ) 
        {
            fail=true;
            return ;
        }
        
        for(int i=st[rt];i<=ed[rt];i++)
            if(son[i]!=f && !broken[rt][son[i]] )
                dfs(son[i],rt);
    }
    
    void print()
    {
        for(int i=1;i<=n;i++)
            printf("%d ",ans[i]);
        printf("
    ");
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        int u,v;
        for(int i=1;i<=m;i++)
            scanf("%d%d",&u,&v),
            add(u,v);
        
        for(int i=1;i<=n;i++)//把son变成一段段排好序的序号,用于dfs 
        {
            st[i]=cnt+1;
            for(int j=head[i];j;j=e[j].nx )
                son[++cnt]=e[j].v ;
            ed[i]=cnt;
            sort(son+st[i],son+ed[i]+1);
        }
        if(m<n)
            pos=0,dfs(1,0),print();
        else
        {
            for(int i=1;i<=n;i++)
                in[i]=ed[i]-st[i]+1;
            topo();
            for(int i=1;i<tot;i+=2)
            {
                int u=e[i].v ,v=e[i+1].v ;
                if(in[u]==1 || in[v]==1) continue;
                
                broken[u][v]=broken[v][u]=true;
                fail=change=false;
                pos=0,dfs(1,0);
                broken[u][v]=broken[v][u]=false;
            }
            print();
        }
        
        return 0;
    }

    n^2的复杂度

    https://www.cnblogs.com/mangoyang/p/9314823.html 

    https://www.luogu.org/problem/P5021

    https://www.luogu.org/problem/P4654

  • 相关阅读:
    PHP学习笔记一
    抓取【你懂的】应用的数据
    抓取[今日新闻]应用的数据
    开源项目Html Agility Pack实现快速解析Html
    澳大利亚玩全攻略(图文全彩版)
    畅游夏威夷,看这本就够了
    科学丨光的折射
    未解之谜.下
    科学是什么
    大脑奥秘知多少:脑科学初探
  • 原文地址:https://www.cnblogs.com/xwww666666/p/11710212.html
Copyright © 2011-2022 走看看