2018 ICPC沈阳网络赛 F. Fantastic Graph (上下界网络流)

题目链接

给出一个二分图,问能否删去某些边,使得每个点的度都在[l,r]范围内。

建一个源汇,分别从源点向x部、y部向汇点连边。这样就变成了一个有源汇上下界可行流的问题。

建一个超级源汇,对于每条从u到v流量范围为[l,r]的边,从u到v连边容量为r-l,从超级源点到v连边容量为l,从u到超级汇点连边容量为l。如果最大流等于(n+m)*l则存在可行流。

以及今天发现以前用的dinic模板辣鸡的一批……换了个优化的嘤嘤嘤

从2000ms到65ms……

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 4050;
const int INF = 0x3f3f3f3f;
const ll mod = 1000000007;

int n, m, k, s, t, S, T;
int l, r, no, a, b;
int head[maxn], level[maxn];
struct node
{
    int to, nxt;
    int f;
}e[maxn * 7];
void add(int a, int b, int w)
{
    e[no].to = b, e[no].nxt = head[a], e[no].f = w;
    head[a] = no++;
    e[no].to = a, e[no].nxt = head[b], e[no].f = 0;
    head[b] = no++;
}

bool bfs(int s, int t)
{
    memset(level, -1, sizeof(level));
    level[s] = 0;
    queue<int>q;
    q.push(s);
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        for(int i = head[u];i != -1;i = e[i].nxt)
        {
            int v = e[i].to;
            if(level[v] == -1 && e[i].f > 0)
            {
                level[v] = level[u] + 1;
                q.push(v);
                if(v == t) return true;
            }
        }
    }
    return level[t] != -1;
}

int dfs(int s, int t, int f)
{
    if(s == t || f == 0) return f;
    int tmp, ret = 0;
    for(int i = head[s];i != -1;i = e[i].nxt)
    {
        int v = e[i].to;
        if(level[v] == level[s] + 1 && e[i].f > 0 && (tmp = dfs(v, t, min(f, e[i].f))))
        {
            e[i].f -= tmp;
            e[i^1].f += tmp;
            ret += tmp;
            f -= tmp;
            if(f == 0) break;
        }
    }
    if(f > 0) level[s] = -1;
    return ret;
}

int dinic(int s, int t)
{
    int res = 0;
    while(bfs(s, t))
    {
        int tmp = dfs(s, t, INF);
        res += tmp;
    }
    return res;
}

int main()
{
    int kase = 0;
    while(scanf("%d%d%d", &n, &m, &k) != EOF)
    {
        no = 0;
        memset(head, -1, sizeof(head));
        s = n+m + 1, t = n+m + 2;
        S = 0, T = n+m + 3;
        scanf("%d%d", &l ,&r);
        for(int i = 0;i < k;i++)
        {
            scanf("%d%d", &a, &b);
            add(a, b + n, 1);
        }
        add(t, s, INF);
        for(int i = 1;i <= n;i++)
        {
            add(s, i, r - l);
            add(S, i, l), add(s, T, l);
        }
        for(int i = 1;i <= m;i++)
        {
            add(i + n, t, r - l);
            add(i + n, T, l), add(S, t, l);
        }
        printf("Case %d: ", ++kase);
        int ans = dinic(S, T);
        if(ans == (n + m)*l) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/NPU_SXY/article/details/82589176