其他分享
首页 > 其他分享> > # NOIP2018_旅行

# NOIP2018_旅行

作者:互联网

解:


观察数据范围,图的形态为树或基环树

当为树时,显然,从1号点类似于贪心dfs一遍即可

当为基环树时,一定有一边不会被经过,所以标记所有环上的边

再枚举删哪一条边,然后按树一样dfs即可

代码:


满目疮痍的代码

对于原题来说,还需要各种优化卡常

发现普通卡常效果不大,程序98%以上的时间都在删边,再跑dfs

所以要用空间换时间,5000*5000的数组还是开的起的

添加各种记忆化,如果计算过了就不再重复计算

结果:最高600+ms,空间70+mb

#include <bits/stdc++.h>
using namespace std;
const int N = 5010;
// typedef unsigned long long ull;
//#####################
// ull sol_st, sol_ed;
//#####################
int n, m;

// ull get_clock(){
//  ull ret;
//  __asm__ __volatile__ ("rdtsc\n\t":"=A"(ret):);
//  return ret;
// }

inline int read() {
    int re = 0, f = 1; char ch = getchar();
    while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); }
    while (isdigit(ch)) re = re * 10 + ch - 48, ch = getchar();
    return re * f;
}

int head[N], ver[N << 1], nxt[N << 1], tot;
bool del[N];

struct EDGE{
    int u, v;
}e[N << 1];
void add(int u, int v) { ver[++tot] = v; nxt[tot] = head[u]; head[u] = tot; }

int ans[N], res[N], resnum;
bool vis[N];

namespace SOLVE_1{
    void dfs(int now) {
        ans[++resnum] = now;
        vis[now] = true;
        for (int i = head[now]; i; i = nxt[i]) {
            int y = ver[i];
            if (vis[y]) continue;
            dfs(y);
        }
    }

    void main() {
        dfs(1);
    }
}

namespace SOLVE_2{
    // map<pair<int, int>, bool> bridge;
    // map<pair<int, int>, bool> del;
    bool bridge[N][N];
    bool del[N][N];
    bool calc[N][N];
    int dfn[N], low[N];
    int num;

    void tarj(int now, int fa) {
        dfn[now] = low[now] = ++num;
        for (int i = head[now]; i; i = nxt[i]) {
            int y = ver[i];
            // if (y == fa) continue;
            if (!dfn[y]) {
                tarj(y, now);
                low[now] = min(low[now], low[y]);
                if (low[y] > dfn[now]) 
                    // bridge[make_pair(now, y)] = true,
                    // bridge[make_pair(y, now)] = true;
                    bridge[now][y] = bridge[y][now] = true;
            } else if (y ^ fa)
                low[now] = min(low[now], dfn[y]);
        }
    }
    void dfs(int now) {
        vis[now] = true;
        res[++resnum] = now;
        for (int i = head[now]; i; i = nxt[i]) {
            int y = ver[i];
            // if (vis[y] || del[make_pair(now, y)]) continue;
            if (vis[y] || del[now][y]) continue;
            dfs(y);
        }
    }
    inline bool update() {
        for (int i = 1; i <= n; i++)
            if (ans[i] ^ res[i])
                return ans[i] > res[i];
        return false;
    }

    void main() {
        memset(ans, 0x3f, sizeof ans);
        tarj(1, 0);

        // sol_st = get_clock();
        for (int i = 1; i <= n; i++)
            for (int j = head[i]; j; j = nxt[j]) {
                int y = ver[j];
                // if (bridge[make_pair(i, y)]) continue;
                if (bridge[i][y]) continue;
                if (calc[i][y]) continue;
                memset(vis, 0, sizeof vis);
                resnum = 0;
                // del[make_pair(i, y)] = true;
                // del[make_pair(y, i)] = true;
                del[y][i] = del[i][y] = true;
                calc[y][i] = calc[i][y] = true;
                dfs(1);
                // del[make_pair(i, y)] = false;
                // del[make_pair(y, i)] = false;
                del[y][i] = del[i][y] = false;
                if (update())
                    memcpy(ans, res, sizeof res);
            }
        // for (int i = 1; i <= n; i++)
        //  for (int j = head[i]; j; j = nxt[j]) {
        //      int y = ver[j];
        //      if (bridge[make_pair(i, y)] == false)
        //          cout << "###ring on : " << i << " " << y << endl;
        //  }
        // sol_ed = get_clock();
    }
}

int main() {
    // freopen("P5022_23.in", "r", stdin);
    // freopen("P5022_23.ans", "w", stdout);

    // ull main_st = get_clock();

    n = read(); m = read();
    for (int i = 1; i <= m; i++) {
        int u, v;
        u = read(); v = read();
        add(u, v); add(v, u);
        e[i].u = u; e[i].v = v;
    }

    int tmp[N];
    for (int i = 1; i <= n; i++) {
        memset(tmp, 0, sizeof tmp);
        for (int j = head[i]; j; j = nxt[j])
            tmp[++tmp[0]] = ver[j];
        sort(tmp + 1, tmp + 1 + tmp[0]);
        for (int j = head[i], k = 1; j; j = nxt[j], k++)
            ver[j] = tmp[k];
    }

    if (m == n - 1) SOLVE_1::main();
    else            SOLVE_2::main();
    // for (int i = 1; i <= n; i++) {
    //  cout << "#### " << i << endl;
    //  for (int j = head[i]; j; j = nxt[j])
    //      cout << ver[j] << " ";
    //  cout << endl;
    // }
    for (int i = 1; i <= n; i++)
        printf("%d ", ans[i]);
    puts("");

    // ull main_ed = get_clock();
    // printf("%.7lf", (sol_ed - sol_st) / ((double)main_ed - main_st));
}

标签:旅行,ch,bridge,int,NOIP2018,bool,low,now
来源: https://www.cnblogs.com/Xiwon/p/13435196.html