Codeforces Gym 100825F Transportation Delegation (最大流)

题目大意:

就是现在有s个州, 每个州要么有工厂要么有原材料供应商或者什么都没有, 有的话只有一家

现在有t个运输公司分别提供运输服务

要求一个工厂只能匹配一个供应商,一个供应商只能供应一个工厂,且要满足一个运输公司只为其中一个匹配对服务(可以通过多个运输公司一起来传递来配对一个工厂和供应商)

问最大匹配对数


大致思路:

EC-final前最后一个题.....打完之后训练就结束了呢= =

表示这个题真是让我见识到了什么叫网络流不知道可不可以,先来一发T了再说...简直暴力出奇迹

可以考虑这么建图:

所有工厂和源点连一条容量为1的边, 然后供应商和汇点连一条容量为1的边

对于每一个运输公司,抽象出两个点p1, p2,连一条容量为1的边来控制公司只用一次

对于每一个该运输公司可以服务的点与p1连一条容量1的边, 与p2连一条容量1的边

于是跑一遍最大流就是答案了

这个图最坏情况下应该是1000*2+600+2个点

600*2*1000+1000+600条无向边(120W...)

然而网络流单组数据只跑了159ms.....好强大...


代码如下:

Result  :  Accepted     Memory  :  37712 KB     Time  :  156 ms

/*
 * Author: Gatevin
 * Created Time:  2015/12/11 0:11:10
 * File Name: Yukinoshita_Yukino.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;

#define maxn 2700

#define maxm 1202000

struct Edge
{
    int u, v, nex, cap;
    Edge(){}
    Edge(int _u, int _v, int _nex, int _cap)
    {
        u = _u, v = _v, nex = _nex, cap = _cap;
    }
};

Edge edge[maxm << 1];
int E;
int head[maxn];

void add_Edge(int u, int v, int c)
{
    edge[++E] = Edge(u, v, head[u], c);
    head[u] = E;
    edge[++E] = Edge(v, u, head[v], 0);
    head[v] = E;
}

int dep[maxn];

bool bfs(int start, int end)
{
    int Q[maxn];
    int l, r;
    l = r = 0;
    memset(dep, -1, sizeof(dep));
    Q[r++] = start;
    dep[start] = 0;
    while(l != r)
    {
        int u = Q[l++];
        if(l == maxn) l = 0;
        for(int i = head[u]; i + 1; i = edge[i].nex)
        {
            int v = edge[i].v;
            if(edge[i].cap > 0 && dep[v] == -1)
            {
                dep[v] = dep[u] + 1;
                Q[r++] = v;
                if(r >= maxn) r = 0;
                if(v == end) return 1;
            }
        }
    }
    return 0;
}



int dinic(int start, int end)
{
    int res = 0;
    int top;
    int cur[maxn];
    int stack[maxn];
    while(bfs(start, end))
    {
        memcpy(cur, head, sizeof(head));
        int u = start;
        top = 0;
        while(1)
        {
            if(u == end)
            {
                int min = 1e9;
                int loc;
                for(int i = 0; i < top; i++)
                    if(min > edge[stack[i]].cap)
                    {
                        min = edge[stack[i]].cap;
                        loc = i;
                    }
                for(int i = 0; i < top; i++)
                {
                    edge[stack[i]].cap -= min;
                    edge[stack[i] ^ 1].cap += min;
                }
                res += min;
                top = loc;
                u = edge[stack[top]].u;
            }
            for(int i = cur[u]; i + 1; cur[u] = i = edge[i].nex)
                if(edge[i].cap != 0 && dep[u] + 1 == dep[edge[i].v])
                    break;
            if(cur[u] != -1)
            {
                stack[top++] = cur[u];
                u = edge[cur[u]].v;
            }
            else
            {
                if(top == 0) break;
                dep[u] = -1;
                u = edge[stack[--top]].u;
            }
        }
    }
    return res;
}

map<string, int> M;

int main()
{
    ios::sync_with_stdio(0);
    E = -1;
    memset(head, -1, sizeof(head));
    int s, r, f, t;
    cin>>s>>r>>f>>t;
    string name;
    int S = 0, T = s + 2*t + 1;
    int cnt = 0;
    for(int i = 0; i < r; i++)
    {
        cin>>name;
        if(M.count(name) == 0)
        {
            M[name] = ++cnt;
            add_Edge(S, cnt, 1);
        }
    }
    for(int i = r + 1; i <= r + f; i++)
    {
        cin>>name;
        if(M.count(name) == 0)
        {
            M[name] = ++cnt;
            add_Edge(cnt, T, 1);
        }
    }
    for(int i = 1; i <= t; i++)
    {
        int x;
        cin>>x;
        int point1 = ++cnt, point2 = ++cnt;
        add_Edge(point1, point2, 1);
        while(x--)
        {
            cin>>name;
            if(M.count(name) == 0)
                M[name] = ++cnt;
            int num = M[name];
            add_Edge(num, point1, 1);
            add_Edge(point2, num, 1);
        }
    }
    cout<<dinic(S, T)<<endl;
    return 0;
}



你可能感兴趣的:(codeforces,最大流,Gym,100825F)