您的位置:首页 > 编程语言 > C语言/C++

ZOJ 3642 多重匹配 离散化.cpp

2012-09-21 20:28 155 查看
[b]题意:[/b]

已知一些小孩所拥有的信息和他最多共享信息量和最少共享信息量 问其中某一个小孩最多得到的信息量

给出n表示有n个小孩

接下来n行有 a b c a1 a2 a3 a4 ... ai 表示该小孩有信息a条 最少共享 b 条 最多共享 c 条 其中a1 a2 a3~ai为小孩拥有信息id号

给出一个m 问的是小孩m最多得到的信息量



[b]思路:[/b]

鉴于这道题中信息id号从 0 ~ 200 但是每个小孩最初最多知道10条信息..

所以为了防止遍历的时候太浪费时间 应该把题目id号变成连续的..

然后可以用多重匹配或者最大流来做..

[b]Tips:[/b]

多重匹配的建图方法:

以信息为 集合X 孩子为 集合Y

然后 limit 为 Y 集合的最大容量 即孩子的最大共享量 但是孩子 m 的容量为INF

最大流的建图方法:

一个超级源点..连接孩子 除了第m个孩子之外..

别的孩子都连线..容量为最大分享量..而第m个孩子的容量为INF 表示可以接受无穷多的信息

然后每个孩子和对应的信息连线 容量为1

每个信息又与超级汇点连线 容量为1

求超级源点到超级汇点的最大流既是答案

[b]Code:[/b]

多重匹配

#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
#define clr(x) memset(x, 0, sizeof(x))
const int INF = 0x1f1f1f1f;

bool G[410][210];
int limit[410];
bool vis[410];
int v1, v2, sum;
int v[410];
int vv[210][410];
int num[1000010];

bool find(int u)
{
int i, j, k;
for(i = 0; i < v2; ++i) {
if(G[u][i] && !vis[i]) {
vis[i] = true;
if(v[i] < limit[i]) {
vv[i][v[i]++] = u;
return true;
}

for(j = 0; j < v[i]; ++j) {
if(find(vv[i][j])) {
vv[i][j] = u;
return true;
}
}
}
}
return false;
}

void solve()
{
clr(vis);
sum = 0;
for(int i = 1; i <= v1; ++i) {
clr(vis);
if(find(i)) {
sum++;
}
}
}

int main()
{
int i, j, k;
int n, m, tmp, tt;
while(scanf("%d", &n) != EOF)
{
clr(G), clr(num);
tt = 1;

for(i = 0; i < n; ++i) {
scanf("%d%*d%d", &m, &limit[i]);
while(m--) {
scanf("%d", &tmp);
if(num[tmp] == 0) num[tmp] = tt++;
G[num[tmp]][i] = true;
}
}

v1 = tt-1;
v2 = n;
scanf("%d", &m);

limit[m-1] = INF;
solve();

printf("%d\n", sum);
}
return 0;
}


[b]题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4810[/b]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: