# 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