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.
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.
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.
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
Case 1:
169
Case 2:
139
思路:这个我自己想的话,怎么也不会想到最小割,因为对最小割没什么概念,因为训练指南上面说了是最小割的题,所以我就往那方面想,最后还是想到了。建图的方法首先我们把所有的申请分成两个集合,假设为X,Y,那么我们加一个源点和汇点,源点连向X中所有的点,容量是申请的价格,所有Y的点连向汇点,容量同样为价格。然后如果选了X中的xi会导致Y中的某些点不能选的话,就连一条由x到y的边,容量为无穷大。建好图后,我们要做的就是在这个图里面删掉一些边,使得源点和终点不连通,因为如果连通的话,表示是存在矛盾。然后我们要最大值,就是删掉边之后,留下来的边的容量总和要最大,即删掉的边的容量要最小,就是最小割。根据最小割最大流定理,最大流的值等于最小割的值。最后要注意的是建图的时候不要写复杂了,会超时的。具体怎么搞看代码。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 3000+5;
const int inf = 1e8;
int n1 , n2 , sum;
int service[300005];
struct Edge
{
Edge(int u,int v,int flow,int cap) : u(u) , v(v) , flow(flow) , cap(cap) { }
int u , v;
int flow , cap;
};
vector<Edge> edge;
vector<int> G[2*maxn];
struct Bid
{
vector<int> channel;
int price;
}X[maxn],Y[maxn];
void add(int s,int t,int cap)
{
edge.push_back(Edge(s,t,0,cap));
edge.push_back(Edge(t,s,0,0));
int x = edge.size();
G[s].push_back(x-2);
G[t].push_back(x-1);
}
char buffer[1000];
void input()
{
sum = 0;
memset(service,-1,sizeof(service));
scanf("%d",&n1);
for (int i = 1 ; i <= n1 ; ++i) {
Bid & bid = X[i];
bid.channel.clear();
scanf("%d",&bid.price);
sum += bid.price;
gets(buffer);
char * p = strtok(buffer," ");
while (p) {
int x; sscanf(p,"%d",&x);
service[x] = i;
bid.channel.push_back(x);
p = strtok(NULL," ");
}
}
scanf("%d*c",&n2);
edge.clear();
for (int i = 0 ; i < n1+n2+2 ; ++i) G[i].clear();
for (int i = 1 ; i <= n2 ; ++i) {
Bid & bid = Y[i];
bid.channel.clear();
scanf("%d",&bid.price);
sum += bid.price;
gets(buffer);
char * p = strtok(buffer," ");
while (p) {
int x; sscanf(p,"%d",&x);
if (service[x]!=-1) add(service[x],i+n1,inf);
bid.channel.push_back(x);
p = strtok(NULL," ");
}
}
}
void BuildGraph()
{
for (int i = 1 ; i <= n1 ; ++i)
add(0,i,X[i].price);
for (int i = 1 ; i <= n2 ; ++i)
add(n1+i,n1+n2+1,Y[i].price);
}
struct ISAP
{
int num[maxn*2] , d[maxn*2] , p[maxn*2] , cur[maxn*2];
int s , t , n;
void bfs() {
queue<int> q; q.push(t);
for (int i = 0 ; i < n ; ++i) d[i] = inf;
d[t] = 0;
while (q.size())
{
int u = q.front(); q.pop();
for (int i = 0 ; i < G[u].size() ; ++i)
{
Edge & e = edge[G[u][i]];
if (e.cap==0 && d[e.v]==inf) {
d[e.v] = d[u]+1;
q.push(e.v);
}
}
}
}
int Augment() {
int a = inf , x = t;
while (x!=s) {
Edge & e = edge[p[x]];
a = min(a,e.cap-e.flow);
x = e.u;
}
x = t;
while (x!=s) {
edge[p[x]].flow += a;
edge[p[x]^1].flow -= a;
x = edge[p[x]].u;
}
return a;
}
int maxflow(int s,int t,int n) {
this->s = s , this->t = t , this->n = n;
memset(num,0,sizeof(num));
memset(cur,0,sizeof(cur));
bfs();
for (int i = 0 ; i < n ; ++i)
if (d[i]!=inf) ++num[d[i]];
int x = s , flow = 0;
while (d[s] < n) {
if (x==t) {
flow += Augment();
x = s;
}
bool ok = false;
for (int i = cur[x] ; i < G[x].size() ; ++i)
{
Edge & e = edge[G[x][i]];
if (e.cap > e.flow && d[e.v]+1==d[x]) {
p[e.v] = G[x][i];
cur[x] = i;
ok = true;
x = e.v;
break;
}
}
if (!ok) {
int k = n-1;
for (int i = 0 ; i < G[x].size() ; ++i) {
Edge & e = edge[G[x][i]];
if (e.cap > e.flow) k = min(k,d[e.v]);
}
if (--num[d[x]]==0) break;
++num[d[x]=k+1];
cur[x] = 0;
if (x!=s) x = edge[p[x]].u;
}
}
return flow;
}
}solver;
int main()
{
int T; cin>>T;
int k = 0;
while (T--) {
++k;
input();
BuildGraph();
printf("Case %d:\n%d\n",k,sum-solver.maxflow(0,n1+n2+1,n1+n2+2));
if (T) printf("\n");
}
}