1. 程式人生 > >noip 2018 d2t1 旅行

noip 2018 d2t1 旅行

最大值 城市 continue efi 上一個 並且 code 起點 tmp

noip 2018 d2t1 旅行


題目來自洛谷

給定n個城市,m條雙向道路的圖, 不存在兩條連接同一對城市的道路,也不存在一條連接一個城市和它本身的道路。並且, 從任意一個城市出發,通過這些道路都可以到達任意一個其他城市。小 Y 只能通過這些道路從一個城市前往另一個城市。

小 Y 的旅行方案是這樣的:任意選定一個城市作為起點,然後從起點開始,每次可 以選擇一條與當前城市相連的道路,走向一個沒有去過的城市,或者沿著第一次訪問該 城市時經過的道路後退到上一個城市。當小 Y 回到起點時,她可以選擇結束這次旅行或 繼續旅行。需要註意的是,小 Y 要求在旅行方案中,每個城市都被訪問到。(註意:同一條道路不能走兩遍,也就是回頭路只能走一次)

為了讓自己的旅行更有意義,小 Y 決定在每到達一個新的城市(包括起點)時,將 它的編號記錄下來。她知道這樣會形成一個長度為 nn 的序列。她希望這個序列的字典序 最小,你能幫幫她嗎? 對於兩個長度均為 n 的序列 A和 B,當且僅當存在一個正整數 x,滿足以下條件時, 我們說序列 A 的字典序小於 B。

  • 對於任意正整數 1≤i<x,序列A的第 i 個元素 Ai 和序列 B 的第 i 個元素 Bi 相同。

  • 序列 A 的第 x 個元素的值小於序列 B 的第 x 個元素的值。


輸入格式

輸入文件共 m + 1 行。第一行包含兩個整數 n,m(m ≤ n),中間用一個空格分隔。

接下來 m 行,每行包含兩個整數 u,v (1 ≤ u,v ≤ n),表示編號為 u 和 v 的城市之 間有一條道路,兩個整數之間用一個空格分隔。

輸出格式:

輸出文件包含一行,n 個整數,表示字典序最小的序列。相鄰兩個整數之間用一個空格分隔。


輸入輸出樣例

輸入樣例#1:

6 5 
1 3 
2 3 
2 5 
3 4 
4 6

輸出樣例#1:

1 3 2 5 4 6

輸入樣例#2:

6 6 
1 3 
2 3 
2 5 
3 4 
4 5 
4 6

輸出樣例#2:

1 3 2 4 5 6

說明

【數據規模與約定】

技術分享圖片


題解:

首先考慮m==n-1的情況,這種情況下,我們只需要先貪心的經過每個點所連向的點中最小的點,即可得到答案,直接用vector存圖,對點進行排序,在樹上dfs一遍即可解決,即可得到60分

考慮滿分做法,因為n==m則圖中有且只有一個環,可以想到這個環上肯定有一條邊是不被需要的,因為我們只需要走一遍即可。

我們先找到環,枚舉這個環上的每一條邊刪去,搜索更新答案的最小值,最後輸出最小值即可,時間復雜度n^2

不找環直接暴力刪邊也可過

找環可以拓撲排序,可以並查集,這裏采用一種其他的方法

#include<bits/stdc++.h>
#define maxn 5050
using namespace std;

struct node {
    int v, w;
    node(int vv) {
        v = vv;
    }
};
vector<node> G[maxn], g[maxn];
void adde(int a, int b) {
    G[a].push_back(node(b));
    G[b].push_back(node(a));
}

inline int getnum() {
    int ans = 0; char c; int flag = 1;
    while (!isdigit(c = getchar()) && c != '-');
    if (c == '-') flag = -1; else ans = c - '0';
    while (isdigit(c = getchar())) ans = ans * 10 + c - '0';
    return ans * flag;
}

int n, m;
int vis[maxn];
int cnt = 0;
int ans[maxn], tmp[maxn];
int del[maxn][maxn];

int cmp(node a, node b) {
    return a.v < b.v;
}

void dfs(int u, int f) {//假如n == m - 1,則直接貪心選取較小的邊,對連向的點進行排序直接遍歷圖即可
    ans[++cnt] = u;
    for (int i = 0; i < G[u].size(); i++) {
        int v = G[u][i].v;
        if (v != f)
            dfs(v, u);
    }
}
int num;
int find(int u, int f) {//找環
    if (num) return 0;//假如已經找到了環的起點,則退出搜索,因為此時環已經構建好了
    vis[u] = 1;//已經遍歷過這個點
    for (int i = 0; i < G[u].size(); i++) {
        int v = G[u][i].v;
        if (v == f) continue;
        if (vis[v]) {//假如找到了遍歷過的點,說明形成了環
            num = v;//環的起點為num
            g[u].push_back(node(v));//將構成環的這條邊加入
            return 1;//返回1,代表可以找到環
        }
        if (find(v, u)) {//假如從v開始能找到環的話
            if (v == num) return 0;//如果連向的點就是起點,則返回,因為這條邊不在環內
            g[u].push_back(node(v));//將在環內的邊加入圖g
            return 1;//返回可以找到環,這樣就可以將一整個環內的邊全部加入g
        }
    }
}
void dfs1(int u) {
    if (vis[u]) return;
    vis[u] = 1;
    tmp[++cnt] = u;
    for (int i = 0; i < G[u].size(); i++) {
        int v = G[u][i].v;
        if (del[u][v] == 0) dfs1(v);
    }
}
int check() {
    for (int i = 1; i <= n; i++) {
        if (ans[i] == tmp[i]) continue;
        if (ans[i] > tmp[i]) return 1;
        else return 0;
    }
}

int main() {
    n = getnum(), m = getnum();
    for (int i = 1; i <= m; i++) {
        int a = getnum(), b = getnum();
        adde(a, b);
    }
    for (int i = 1; i <= n; i++) {
        sort(G[i].begin(), G[i].end(), cmp);//排序
    }
    for (int i = 1; i <= n; i++) {
        ans[i] = n;//將ans賦值為最大值
    }
    if (n == m) {
        find(1, -1);
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j < g[i].size(); j++) {
                memset(vis, 0, sizeof(vis));
                int v = g[i][j].v;
                del[i][v] = 1; del[v][i] = 1;//刪邊
                cnt = 0;
                dfs1(1);
                del[i][v] = 0; del[v][i] = 0;//恢復
                if (check()) {
                    for (int i = 1; i <= n; i++) {
                        ans[i] = tmp[i];
                    }
                }
            }
        }
        for (int i = 1; i <= n; i++) {
            cout << ans[i] << " ";
        }
        return 0;
    }
    dfs(1, -1);
    for (int i = 1; i <= cnt; i++) {
        cout << ans[i] << " ";
    }
    return 0;
}

noip 2018 d2t1 旅行