P5295 [北京省选集训2019]图的难题

给定一张无向图,要求把边染成黑白两色,要求所有白色边构成的子图没有环,且所有黑色边构成的子图没有环。

1T10,n500,1031 \leq T \leq 10,n \leq 500, \leq 10^3,时限 2s2\text{s},空限 250MB250\text{MB}

std

首先有结论 11:如果原图存在一个非空子图满足 E>2V2|E|>2|V|−2,那么显然无解。

简略证明:

假设图中有 2V22|V| - 2 条边,那么此时为了符合条件,解中一定有一棵白色生成树和一棵黑色生成树。

考虑到如果再多加入一条边,那么一定是在两棵树中的一棵加上一条边,此时一定会产生环,无解。

所以 maxE=2V2\max_{E}=2|V|-2

然后有结论 22:如果图 GG 的每一个非空子图都满足 E2V2|E|≤2|V|−2,那么它一定是丛林。

咕咕咕。

#include <bits/stdc++.h>

using namespace std;

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;
}

inline void write(int x)
{
    if (x < 0)
    {
        putchar('-');
        x = -x;
    }
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}

typedef int tp;

const int _ = 5e4 + 10;

int n, m, s, t, lv[_], cur[_];

int tot = 1, head[_], to[_ << 1], nxt[_ << 1];

tp w[_ << 1];

inline void add(int u, int v, tp dis)
{
    to[++tot] = v;
    nxt[tot] = head[u];
    w[tot] = dis;
    head[u] = tot;
}

inline void Add(int u, int v, tp dis)
{
    add(u, v, dis);
    add(v, u, 0);
}

inline bool bfs()
{
    memset(lv, -1, sizeof(lv));
    lv[s] = 0;
    memcpy(cur, head, sizeof(head));
    queue<int> q;
    q.push(s);
    while (!q.empty())
    {
        int p = q.front();
        q.pop();
        for (int eg = head[p]; eg; eg = nxt[eg])
        {
            int v = to[eg];
            tp vol = w[eg];
            if (vol > 0 && lv[v] == -1)
                lv[v] = lv[p] + 1, q.push(v);
        }
    }
    return lv[t] != -1;
}

tp dfs(int p = s, tp flow = 2e9)
{
    if (p == t)
        return flow;
    tp rmn = flow;
    for (int eg = cur[p]; eg && rmn; eg = nxt[eg])
    {
        cur[p] = eg;
        int v = to[eg];
        tp vol = w[eg];
        if (vol > 0 && lv[v] == lv[p] + 1)
        {
            tp c = dfs(v, min(vol, rmn));
            rmn -= c;
            w[eg] -= c;
            w[eg ^ 1] += c;
        }
    }
    return flow - rmn;
}

inline tp dinic()
{
    tp ans = 0;
    while (bfs())
        ans += dfs();
    return ans;
}

signed main()
{
    int T = read(), x, y;
    while(T--)
    {
    	tot = 1;
    	memset(head, 0, sizeof head);
        n = read(), m = read();
        s = n + m + 1, t = s + 1;
    	for(int i = 1;  i <= n; ++i)
    		Add(i, t, 2);
        for (int i = 1; i <= m; i++)
        {
        	x = read(), y = read();
        	Add(s, i + n, 1);
        	Add(i + n, x, 2e9);
        	Add(i + n, y, 2e9);
		}
		int ans = dinic();
		for(int i = 2; i <= 2 * n; i += 2)
		{
			s = i / 2, t = n + m + 1;
			ans -= dinic();
			w[i] = 0;
			s = n + m + 1, t = s + 1;
			ans += dinic();
			if(m - ans >= 1)
			{
				printf("No\n");
				goto END;
			}
			w[i] = 2;
		}
        printf("Yes\n");
        END:;
    }
    return 0;
}
posted @ 2022-03-04 13:45  蒟蒻orz  阅读(3)  评论(0编辑  收藏  举报  来源