P1402 酒店之王

好吧,承认不会。


这道题我拿到的时候就知道是一种最大匹配,要跑网络流的。

然后发现有两个事物要匹配。

我的第一感觉是:建两张图,一起跑,跑完取\(min\)就行了。

后来猛然发现:最大匹配可以有多种答案,而我们只能列出其中一种。

两个值取min是错误的,因为有可能改变匹配顺序能使答案更优。

所以我毫不犹豫地翻题解。。。恍然大悟!

原来可以把人夹在中间,上下弄两个二分图!

因为连的是喜欢的边,所以只要有一个流量,就满足了一个人。

题解中还说到了一点:人可能被多次利用!

所以拆点,像那道求最小割点的题目一样,把一个点变成两个点中间一条有向边。

然后就可以解决了。

三倍经验:

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn = 2005, INF = 0x3f3f3f3f;
int n, p, q, s, t;
struct Edges
{
    int next, to, weight;
} e[2000005];
int head[maxn], tot = 1;
int queue[1000005], front, rear;
int dep[maxn], cur[maxn];
int read()
{
    int ans = 0; char ch = getchar();
    while(ch > '9' || ch < '0') ch = getchar();
    while(ch >= '0' && ch <= '9')
    {
        ans = ans * 10 + ch - '0';
        ch = getchar();
    }
    return ans;
}
void link(int u, int v, int w)
{
    e[++tot] = (Edges){head[u], v, w};
    head[u] = tot;
}
void Add_Edges(int u, int v, int w)
{
    link(u, v, w);
    link(v, u, 0);
}
void init()
{
    for(int i = 2 * n + 1; i <= 2 * n + p; i++) Add_Edges(s, i, 1);
    for(int i = 1; i <= n; i++) Add_Edges(i, i + n, 1);
    for(int i = 2 * n + p + 1; i <= 2 * n + p + q; i++) Add_Edges(i, t, 1);
}
bool bfs()
{
    memset(dep, 0, sizeof(dep));
    front = rear = 0;
    dep[s] = 1; queue[rear++] = s;
    while(front < rear)
    {
        int u = queue[front++];
        for(int i = head[u]; i; i = e[i].next)
        {
            int v = e[i].to;
            if(!dep[v] && e[i].weight)
            {
                dep[v] = dep[u] + 1;
                queue[rear++] = v;
            }
        }
    }
    return dep[t];
}
int dfs(int u, int flow)
{
    if(u == t) return flow;
    for(int i = head[u]; i; i = e[i].next)
    {
        int v = e[i].to;
        if(dep[v] == dep[u] + 1 && e[i].weight)
        {
            int di = dfs(v, std::min(flow, e[i].weight));
            if(di)
            {
                e[i].weight -= di;
                e[i ^ 1].weight += di;
                return di;
            }
        }
    }
    return 0;
}
int dinic()
{
    int ans = 0;
    while(bfs())
    {
        //for(int i = 1; i <= 2 * n + p + q + 2; i++) cur[i] = head[i];
        while(int temp = dfs(s, INF)) ans += temp;
    }
    return ans;
}
int main()
{
    //freopen("in.txt", "r", stdin);
    n = read(), p = read(), q = read();
    //[1, n]鏄汉锛孾1 + n, n + n]鏄汉鐨勭浜岀粨鐐?
    //[2 * n + 1, 2 * n + p]鏄埧闂?
    //[2 * n + p + 1, 2 * n + p + q]鏄彍
    s = 2 * n + p + q + 1; t = s + 1;
    init();
    for(int i = 1; i <= n; i++)
    {
        for(int j = 2 * n + 1; j <= 2 * n + p; j++)
        {
            int ord = read();
            if(ord) Add_Edges(j, i, 1);
        }
    }
    for(int i = 1; i <= n; i++)
    {
        for(int j = 2 * n + p + 1; j <= 2 * n + p + q; j++)
        {
            int ord = read();
            if(ord) Add_Edges(i + n, j, 1);
        }
    }
    printf("%d\n", dinic());
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Garen-Wang/p/9250884.html