题解:AT_abc412_d [ABC412D] Make 2-Regular Graph
题目简述
给你一张顶点编号为
主要思路
不难发现,想要使每个顶点的度数均为
虽然这个枚举中会有因为是环而重复的情况(例如 1 2 3 4 和 2 3 4 1),但
枚举出一种排列后,计算需要添加或删除一条边的最少次数时,可以先计算出需要添加几条边,那么边的存储就可以使用邻接矩阵而方便计算,假设排列为
于是就可以写下以下搜索代码:
// use 表示排列,vis 表示是否已经出现在排列中
void dfs(int u) {
if (u > n) {
int res = 0;
for (int i = 1; i <= n; i++) res += !edge[use[i]][use[i % n + 1]];
res += m + res - n;
res += m + res - n;
ans = min(ans, res);
return;
}
for (int i = 1; i <= n; i++) {
if (vis[i]) continue;
use[u] = i;
vis[i] = true;
dfs(u + 1);
vis[i] = false;
}
}
随后你就会发现过不了样例#3,并且如果你按刚才的思路来算根本就得不到正确答案
因为题目中只要求了每个顶点的度数为
由于一个要使每个顶点的环的顶点数要
注意事项
在枚举第一个环时起始点加长度不是一定要 1 3 5 2 4 那么 2 4 1 也是一个环。
AC Code
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#ifdef ONLINE_JUDGE
#define getchar getchar_unlocked
#endif
template<typename T> void read(T &x) { int f = 1; x = 0; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-')f = -1; ch = getchar(); }while (isdigit(ch)) { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); }x *= f; }
template<typename T, typename ...Args> void read(T &x, Args &...args) { read(x); read(args...); }
template<typename T> void print(T x) { if (x < 0) { putchar('-'); x = -x; }if (x > 9) { print(x / 10); }putchar(char(x % 10 + 48)); }
template<typename T, typename ...Args> void print(T x, Args ...args) { print(x); putchar(' '); print(args...); }
typedef long long ll;
typedef long double db;
const int N = 8 + 10;
const int INT_INF = 0x3f3f3f3f;
// ----------------------------
// ----------------------------
bool vis[N], edge[N][N];
int n, m, ans = INT_INF, use[N];
// ----------------------------
void dfs(int u) {
if (u > n) {
int res = 0;
for (int i = 1; i <= n; i++) res += !edge[use[i]][use[i % n + 1]];
res += m + res - n;
ans = min(ans, res);
int r;
for (int len = 3; len <= n - 3; len++) {
for (int l = 1; l <= n; l++) {
res = 0;
if (l <= n - len + 1) r = l + len - 1;
else r = (l + len) % n - 1;
for (int i = l; i != r % n + 1; i = i % n + 1) {
if (i != r) res += !edge[use[i]][use[i % n + 1]];
else res += !edge[use[i]][use[l]];
}
for (int i = r % n + 1; i != l; i = i % n + 1) {
if (i != (l + n - 2) % n + 1) res += !edge[use[i]][use[i % n + 1]];
else res += !edge[use[i]][use[r % n + 1]];
}
res += m + res - n;
ans = min(ans, res);
}
}
return;
}
for (int i = 1; i <= n; i++) {
if (vis[i]) continue;
use[u] = i;
vis[i] = true;
dfs(u + 1);
vis[i] = false;
}
}
int main() {
int u, v; read(n, m);
for (int i = 1; i <= m; i++) {
read(u, v);
edge[u][v] = edge[v][u] = true;
}
// ----------------------------
dfs(1);
// ----------------------------
print(ans);
return 0;
}