1. 程式人生 > >[NOIp2018提高組]旅行

[NOIp2018提高組]旅行

[NOIp2018提高組]旅行:

題目大意:

一個\(n(n\le5000)\)個點,\(m(m\le n)\)條邊的連通圖。可以從任意一個點出發,前往任意一個相鄰的未訪問的結點,或沿著第一次來這個點的邊返回。需要遍歷每一個點。沒經過一個新的結點,就將這個結點寫下來。最終可以得到一個序列。求字典序最小的序列。

思路:

對於樹的情況,顯然從\(1\)出發,每次從字典序最小的相鄰結點DFS即可。

對於有環的情況,由於環只有一個,我們可以將環找出來,列舉刪掉環上的每一條邊,然後按樹的情況求解即可。

時間複雜度\(\mathcal O(n^2)\)

原始碼:

#include<set>
#include<stack>
#include<cstdio>
#include<cctype>
#include<vector>
#include<climits>
#include<algorithm>
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
const int N=5001;
struct Edge {
    int u,v;
};
Edge edge[N];
std::vector<std::pair<int,int> > g[N];
bool vis[N],mark[N];
std::stack<std::pair<int,int> > stk;
void dfs(const int &x,const int &par) {
    vis[x]=true;
    for(unsigned i=0;i<g[x].size();i++) {
        const int &y=g[x][i].first;
        if(y==par) continue;
        stk.push(std::make_pair(x,g[x][i].second));
        if(!vis[y]) {
            dfs(y,x);
        } else {
            int z;
            do {
                z=stk.top().first;
                mark[stk.top().second]=true;
                stk.pop();
            } while(z!=y);
            throw 0;
        }
        stk.pop();
    }
}
std::set<int> e[N];
inline void add_edge(const int &u,const int &v) {
    e[u].insert(v);
    e[v].insert(u);
}
inline void del_edge(const int &u,const int &v) {
    e[u].erase(v);
    e[v].erase(u);
}
int s[N],ans[N];
void solve(const int &x,const int &par) {
    s[++s[0]]=x;
    for(std::set<int>::iterator i=e[x].begin();i!=e[x].end();i++) {
        const int &y=*i;
        if(y==par) continue;
        solve(y,x);
    }
}
inline bool check(int a[],int b[],const int &n) {
    for(register int i=1;i<=n;i++) {
        if(a[i]<b[i]) return true;
        if(a[i]>b[i]) return false;
    }
    return false;
}
int main() {
    const int n=getint(),m=getint();
    for(register int i=0;i<m;i++) {
        const int &u=edge[i].u=getint();
        const int &v=edge[i].v=getint();
        g[u].push_back(std::make_pair(v,i));
        g[v].push_back(std::make_pair(u,i));
    }
    for(register int i=0;i<m;i++) {
        add_edge(edge[i].u,edge[i].v);
    }
    if(m==n-1) {
        solve(1,0);
        for(register int i=1;i<=n;i++) {
            printf("%d%c",s[i]," \n"[i==n]);
        }
        return 0;
    }
    try {
        dfs(1,0);
    } catch(...) {}
    std::fill(&ans[1],&ans[n]+1,INT_MAX);
    for(register int i=0;i<m;i++) {
        if(!mark[i]) continue;
        del_edge(edge[i].u,edge[i].v);
        s[0]=0;
        solve(1,0);
        if(check(s,ans,n)) {
            std::copy(&s[1],&s[n]+1,&ans[1]);
        }
        add_edge(edge[i].u,edge[i].v);
    }
    for(register int i=1;i<=n;i++) {
        printf("%d%c",ans[i]," \n"[i==n]);
    }
    return 0;
}