uva 1212 Duopoly
Description
The mobile network market in country XYZ used to be dominated by two large corporations, XYZ Telecom and XYZ Mobile. The central government recently has realized that radio frequency spectrum is a scarce resource and wants to regulate its usage. The spectrum currently in use is divided into 300,000 channels. Any wireless service provider who wishes to use certain spectrum should apply for licenses on these channels. While some services may require use of multiple channels, a single channel can not be shared by different services.
The central government wants to maximize its revenue from the spectrum by putting the channels up to an auction. The only two bidders are XYZ Telecom and XYZ Mobile. They are allowed to place bids on combinations of channels, through which their services can communicate with the customers. Furthermore, the government stipulates that a company can only place at most one bid on a specific channel.
The government can only accept a subset of the bids so none of them would conflict with each other. However, officials soon find out that it is a difficult task to determine the winning bids in order to maximize the revenue, and they are asking for your help.
Input
Standard input will contain multiple test cases. The first line of the input is a single integer T(1≤T≤10) which is the number of test cases. T test cases follow, each preceded by a single blank line.
Each test case has two bid description sections, which are for XYZ Telecom and XYZ Mobile, respectively. Each section starts with an integer N(1≤N≤3, 000) , which is the number of bids that follow. The next N lines each contain the description for one bid, the first integer P(1≤P≤1, 000) gives the price of that bid, followed by the channel numbers required by this service. A service would require at least 1 channel and at most 32 channels. Each channel number is a positive integer and will never exceed 300,000.
Output
Results should be directed to standard output. Start each case with “Case # : ” on a single line, where # is the case number starting from 1. Two consecutive cases should be separated by a single blank line. No blank line should be produced after the last test case.
For each test case, print the maximized revenue the government is able to collect by issuing licenses on the channels.
Sample Input
2
3
45 1
51 2
62 3
4
54 1
15 2
33 3
2 4 5
5
20 1
18 2
23 4
54 3 5 6
17 7
4
36 1 2 3
28 5
47 4 7
16 6
Sample Output
Case 1:
169
Case 2:
139
题目大意:T公司和M公司想向政府申请一些资源的使用权。每一项申请包含一个资源列表和该公司愿意支付的金额。如果该申请得到批准,该公司将得到列表中所有资源的使用权。政府只能完整的批准或拒绝一个申请,不能只批准申请其中的部分资源,也不能将一个资源的使用权同时批给两个公司。同一个公司的两项申请中保证不包含相同的资源。你的任务是帮助政府决定应当批准那些申请,使得政府收益最大化,即被批准的那些申请的金额之和最大。
解题思路:设置一个超级源点连向公司A的申请,容量为A公司该申请的价格。设置一个超级汇点,使B公司的申请连向超级汇点,容量为B公司该申请的价格。然后把有矛盾的两个申请连起来,容量为INF。建完图,跑一次最大流,求出来的就是最小割,也就是两家公司最小的申请金额,然后用两家公司的总申请金额减去最小的申请金额,就是答案。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <sstream>
using namespace std;
const int N = 10005;
const int M = 9000005;
const int INF = 0x3f3f3f3f;
typedef long long ll;
int n, m, s, t, sum;
struct BID{
int val, chn[35], len;
}B1[3005], B2[3005];
int rec[300005];
int ec, head[N], first[N], que[N], lev[N];
int Next[M], to[M], v[M];
void init() {
sum = 0;
ec = 0;
memset(first, -1, sizeof(first));
memset(rec, 0, sizeof(rec));
}
void addEdge(int a,int b,int c) {
to[ec] = b;
v[ec] = c;
Next[ec] = first[a];
first[a] = ec++;
to[ec] = a;
v[ec] = 0;
Next[ec] = first[b];
first[b] = ec++;
}
int BFS() {
int kid, now, f = 0, r = 1, i;
memset(lev, 0, sizeof(lev));
que[0] = s, lev[s] = 1;
while (f < r) {
now = que[f++];
for (i = first[now]; i != -1; i = Next[i]) {
kid = to[i];
if (!lev[kid] && v[i]) {
lev[kid] = lev[now] + 1;
if (kid == t) return 1;
que[r++] = kid;
}
}
}
return 0;
}
int DFS(int now, int sum) {
int kid, flow, rt = 0;
if (now == t) return sum;
for (int i = head[now]; i != -1 && rt < sum; i = Next[i]) {
head[now] = i;
kid = to[i];
if (lev[kid] == lev[now] + 1 && v[i]) {
flow = DFS(kid, min(sum - rt, v[i]));
if (flow) {
v[i] -= flow;
v[i^1] += flow;
rt += flow;
} else lev[kid] = -1;
}
}
return rt;
}
int dinic() {
int ans = 0;
while (BFS()) {
for (int i = 0; i <= t; i++) {
head[i] = first[i];
}
ans += DFS(s, INF);
}
return ans;
}
void input() {
scanf("%d\n", &n);
string a;
int val, chn;
int cnt;
for (int i = 1; i <= n; i++) {
cnt = 0;
getline(cin, a);
stringstream stream(a);
stream >> val;
sum += val;
B1[i].val = val;
while (stream >> chn) {
B1[i].chn[cnt++] = chn;
rec[chn] = i;
}
B1[i].len = cnt;
}
scanf("%d\n", &m);
for (int i = 1; i <= m; i++) {
cnt = 0;
getline(cin, a);
stringstream stream(a);
stream >> val;
sum += val;
B2[i].val = val;
while (stream >> chn) {
B2[i].chn[cnt++] = chn;
}
B2[i].len = cnt;
}
s = 0, t = n + m + 2;
}
void build() {
for (int i = 1; i <= n; i++) {
addEdge(s, i, B1[i].val);
}
for (int i = 1; i <= m; i++) {
addEdge(i + n, t, B2[i].val);
}
for (int i = 1; i <= m; i++) {
for (int j = 0; j < B2[i].len; j++) {
if (rec[B2[i].chn[j]]) {
addEdge(rec[B2[i].chn[j]], i + n, INF);
}
}
}
}
int main() {
int T, Case = 1;
scanf("%d", &T);
while (T--) {
printf("Case %d:\n", Case++);
init();
input();
build();
printf("%d\n", sum - dinic());
if (T) puts("");
}
return 0;
}