题意:给一张无向图,将其中的边染成黑色或白色,使得不存在同色环。问是否存在可行的染色方案。
观察可知一个结论:图
的可行的染色方案存在,当且仅当对于任意子图
都有
,即
。
如果我们定义一张子图的权值
,那么只要
。比较显然的最大权闭合子图问题:把边看成点,点权为
;点的点权为
。那么我们从源点向代表边的点连边,容量是
;从代表点的点向汇点连边,容量是
;从边对应的点向其两个端点对应的点连边,容量是
表示割不掉;跑最大流,那么
。
但是这样会有问题:空子图的权值
,所以任何一张图都不合法。我们必须让我们的最大流算法不把空子图算进去。做法很简单,我们强制选一个点,那么从这个点对应的点到汇点的边就不连了,最后
。那么强制选哪个点呢?枚举即可。
#include <cctype>
#include <cstdio>
#include <climits>
#include <algorithm>
template <typename T> inline void read(T& x) {
int f = 0, c = getchar(); x = 0;
while (!isdigit(c)) f |= c == '-', c = getchar();
while (isdigit(c)) x = x * 10 + c - 48, c = getchar();
if (f) x = -x;
}
template <typename T, typename... Args>
inline void read(T& x, Args&... args) {
read(x); read(args...);
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + 48);
}
template <typename T> inline void writeln(T x) { write(x); puts(""); }
template <typename T> inline bool chkmin(T& x, const T& y) { return y < x ? (x = y, true) : false; }
template <typename T> inline bool chkmax(T& x, const T& y) { return x < y ? (x = y, true) : false; }
const int maxv = 1607, maxe = 1e5, inf = INT_MAX;
int v[maxe << 1], cap[maxe << 1], flow[maxe << 1], next[maxe << 1], tot = -1;
int head[maxv], curr[maxv], q[maxv], height[maxv];
int s, t, V;
inline void ae(int x, int y, int c) {
v[++tot] = y; cap[tot] = c; flow[tot] = 0; next[tot] = head[x]; head[x] = tot;
v[++tot] = x; cap[tot] = 0; flow[tot] = 0; next[tot] = head[y]; head[y] = tot;
}
inline bool bfs() {
for (int i = 1; i <= V; ++i) height[i] = 0;
int l = 0, r = 1; height[q[1] = s] = 1;
while (l < r) {
int x = q[++l];
for (int i = head[x]; ~i; i = next[i])
if (cap[i] > flow[i] && !height[v[i]])
height[q[++r] = v[i]] = height[x] + 1;
}
return height[t];
}
int dfs(int x, int cf) {
if (x == t || !cf) return cf;
int getf = 0;
for (int i = curr[x]; ~i; i = next[i])
if (cap[i] > flow[i] && height[v[i]] == height[x] + 1) {
int nf = dfs(v[i], std::min(cf, cap[i] - flow[i]));
if (nf) {
flow[i] += nf; flow[i ^ 1] -= nf; getf += nf;
if (!(cf -= nf)) break;
}
}
return getf;
}
inline int maxflow() {
int ans = 0;
while (bfs()) {
for (int i = 1; i <= V; ++i)
curr[i] = head[i];
ans += dfs(s, inf);
}
return ans;
}
struct Edge {
int u, v;
Edge(int x, int y) : u(x), v(y) {}
Edge() : u(0), v(0) {}
};
Edge e[1007];
int T, n, m;
inline bool solve() {
int ans = -inf;
s = n + m + 1;
t = V = s + 1;
for (int u = 1; u <= n; ++u) {
tot = -1;
for (int i = 1; i <= V; i += 4) {
head[i] = -1;
head[i + 1] = -1;
head[i + 2] = -1;
head[i + 3] = -1;
}
for (int i = 1; i <= m; ++i) {
int x = e[i].u, y = e[i].v;
ae(s, i, 1);
ae(i, x + m, inf);
ae(i, y + m, inf);
}
for (int i = 1; i <= n; ++i)
if (i != u) ae(i + m, t, 2);
chkmax(ans, m - 2 - maxflow());
}
return ans <= -2;
}
int main() {
read(T);
while (T--) {
read(n, m);
for (int i = 1; i <= m; ++i) read(e[i].u, e[i].v);
puts(solve() ? "Yes" : "No");
}
return 0;
}