zoukankan      html  css  js  c++  java
  • P5022 旅行 (NOIP2018)

    传送门

    先考虑是一颗树的情况

    求最小的 dfs 序

    显然按儿子编号从小到大dfs

    如果有多一条边怎么办

    显然会有一条边不用走

    直接枚举删那条边然后每次都暴力 dfs

    复杂度 $O(n^2)$

    注意每个节点的儿子顺序先预处理好

    不要每次都重新算

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<vector>
    using namespace std;
    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<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=10007;
    int fir[N],from[N<<1],to[N<<1],cntt;//存排序前的边
    inline void add(int &a,int &b)
    {
        from[++cntt]=fir[a];
        fir[a]=cntt; to[cntt]=b;
    }
    int n,m,ans[N];
    vector <int> v[N];//存排序后的边
    int st[N],t,p1,p2;
    bool vis[N];
    void dfs(int x)//暴力dfs求字典序
    {
        st[++t]=x; vis[x]=1;
        int len=v[x].size();
        for(int i=0;i<len;i++)
        {
            int &to=v[x][i]; if(vis[to]||(p1==x&&p2==to)||(p1==to&&p2==x)) continue;
            dfs(to);
        }
    }
    inline bool pd()//暴力比较字典序大小
    {
        if(t<n) return 0;
        if(!ans[1]) return 1;
        for(int i=1;i<=n;i++)
            if(ans[i]!=st[i])
                return ans[i]<st[i] ? 0 : 1;
    }
    int e[N][2],tmp[N],tot;
    int main()
    {
        freopen("travel.in","r",stdin);
        freopen("travel.out","w",stdout);
        int a,b;
        n=read(); m=read();
        for(int i=1;i<=m;i++)
        {
            a=read(); b=read();
            add(a,b); add(b,a);
            e[i][0]=a; e[i][1]=b;
        }
        for(int i=1;i<=n;i++)//预处理儿子顺序
        {
            tot=0;
            for(int j=fir[i];j;j=from[j]) tmp[++tot]=to[j];
            sort(tmp+1,tmp+tot+1);
            for(int j=1;j<=tot;j++) v[i].push_back(tmp[j]);
        }
        if(m==n-1)
        {
            dfs(1);
            for(int i=1;i<=n;i++) printf("%d ",st[i]);
            return 0;
        }
        for(int i=1;i<=m;i++)
        {
            t=0; p1=e[i][0]; p2=e[i][1];//暴力删边
            for(int i=1;i<=n;i++) vis[i]=0;
            dfs(1);
            if(pd()) for(int i=1;i<=n;i++) ans[i]=st[i];
        }
        for(int i=1;i<=n;i++) printf("%d ",ans[i]);
        return 0;
    }
  • 相关阅读:
    visual studio notes
    使用.net创建activex控件
    在程序中打开/关闭monitor or lcd
    Memory Barrier in Compiler and CPU
    被动工作与主动工作
    排序算法总结
    经典计算机基础数据结构:二叉树
    微软的Challenge文化
    海量数据处理方法的分析
    数组
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/10076260.html
Copyright © 2011-2022 走看看