题解 P5022 【旅行】

题解 P5022 【旅行】

题目链接

一道基环树的题记得我当时在考场连dfs都没想到(我真的是太弱了QAQ)

这道题知道思路其实很简单,当n = m - 1时,图是一个树,直接从第一个点dfs就可以得到答案,n = m时说明图里有一个环,删掉环上的任意一条边就可以让图变成一个数,枚举删除那一条边得到的答案字典序最小即可。

我们老师刚学图就让我们做这道题,总之我觉得用来练习图的基本操作是极好的。这道题我大概交了十几遍才过,因为dfs要求先访问编号最小的节点,所以我第一次一上来用邻接矩阵存图,结果T飞了想想为什么,后来吭哧吭哧自学了邻接链表结果忘了排序......最后做足了功课上std,又T了三个点很明显为什么

仔细琢磨了一下发现一个优化,在n = m时,当我们删除了一条边开始dfs(答案存在res数组里),如果我们发现res[u] > ans[u], 则res一定不比ans优,可以直接跳出,然后你就可以AC最后三个点了。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define ll long long
#define N 5005
using namespace std;

int n, m, tot, vis[N], ans[N], res[N], inp[N][2];
bool ian = 0; //代表res中的答案是否比ans优

vector < int > mp[N];

inline int read()
{
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
    while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
    return x * f;
}

void addedge(int x, int y)
{
    mp[x].push_back(y);
    mp[y].push_back(x);
}

void dfs(int x, int d1, int d2) //d1 d2 表示删除的边连接的节点
{
    vis[x] = true;
    res[++tot] = x;
    if (x < ans[tot]) ian = true; //如果res[x] < ans[x],则无论res后面是什么,res都一定比ans优
    if (x > ans[tot] && !ian) { vis[x] = false; return; } //如果res[x] > ans[x] 且x前面的答案都一样,则res一定没有ans优
    int l = mp[x].size();
    for (int i = 0; i < l; i++)
    {
        if (!vis[mp[x][i]] && !((x == d1 && mp[x][i] == d2) || (x == d2 && mp[x][i] == d1)))
            dfs(mp[x][i], d1, d2);
    }
    vis[x] = false;//别忘了把值赋回去
}

int main()
{
    memset(ans, 0x3f3f3f, sizeof(ans));
    n = read(), m = read();
    for (int i = 1; i <= m; i++)
        addedge(inp[i][0] = read(), inp[i][1] = read());
    for (int i = 1; i <= n; i++)
        sort(mp[i].begin(), mp[i].end()); //一定别忘了排序,不然dfs出来的不一定字典序最小
    if (n == m)//有环
    {
        for (int i = 1; i <= m; i++)//枚举删边
        {
            tot = 0, ian = false;
            dfs(1, inp[i][0], inp[i][1]);
            if (tot != n) continue;
            int flag = false; //res比ans更优
            for (int i = 1; i <= n; i++)
            {
                if (res[i] < ans[i]) { flag = true; break; }
                else if (res[i] > ans[i]) { break; }
            }//看看ans和res哪一个更优
            if (flag)//如果res更优则把res赋给ans
                for (int i = 1; i <= n; i++)
                    ans[i] = res[i];
        }
    }
    else//没有环
    {
        dfs(1, 0, 0);
        for (int i = 1; i <= n; i++)
            ans[i] = res[i];
    }
    for (int i = 1; i <= n; i++)
        cout << ans[i] << " ";//输出答案
    return 0;
}

19.08.18

猜你喜欢

转载自www.cnblogs.com/YuanqiQHFZ/p/11622381.html