(beginer)网络流(最小割最大流) UVA 1212 - Duopoly

来源:互联网 发布:excel筛选出多个数据 编辑:程序博客网 时间:2024/06/04 19:21

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$ \le$T$ \le$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$ \le$N$ \le$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$ \le$P$ \le$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 

2345 151 262 3454 115 233 32 4 5520 118 223 454 3 5 617 7436 1 2 328 547 4 716 6

Sample Output 

Case 1:169Case 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");
}
}
0 0
原创粉丝点击