uva 1212 Duopoly (最小割最大流)

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;
}

版权声明:本文为博主原创文章,未经博主允许也可以转载,不过要注明出处哦。

时间: 2024-10-12 15:22:33

uva 1212 Duopoly (最小割最大流)的相关文章

UVA 1212 - Duopoly(最小割)

UVA 1212 - Duopoly 题目链接 题意:两个公司,每个公司都有n个开价租用一些频道,一个频道只能租给一个公司,现在要求出一个分配方案使得收益最大 思路:最小割,源点连到第一个公司,第二个公司连到汇点,容量均为价钱,然后第一个公司和第二个公司有冲突的就连一条边容量为无穷大,然后求这个图的最小割就是去掉最小多少使得图原图不会冲突了,然后用总金额减去最小割的值即可 代码: #include <cstdio> #include <cstring> #include <q

【BZOJ-1797】Mincut 最小割 最大流 + Tarjan + 缩点

1797: [Ahoi2009]Mincut 最小割 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1685  Solved: 724[Submit][Status][Discuss] Description A,B两个国家正在交战,其中A国的物资运输网中有N个中转站,M条单向道路.设其中第i (1≤i≤M)条道路连接了vi,ui两个中转站,那么中转站vi可以通过该道路到达ui中转站,如果切断这条道路,需要代价ci.现在B国想找出一个路径切断方案

ZOJ3792_Romantic Value(网络流/最小割=最大流/找割边)

解题报告 题目传送门 题意: 给出一个无向图,以及起点与终点.要删除一些边使得起点与终点不连通,在删掉边的权值之和最小的情况下要求删除的边数尽量少. 求出一个比值:剩余边数权值和/删除的边数. 思路: 明显的让起点终点达不到就是一个最小割,用最大流可以求出. 但是求割边边数就不会了,没做过最小割的求割边问题. 割边一定是残留网络中零流的边,但零流不一定是割边. 飞神的想法很奇特.链接传送 可以把残留网络的零流的边设成容量为1,其他设成无穷,再求一次最大流.最后流量一定等于割边边数 另外: 还有一

Destroying The Graph 最小点权集--最小割--最大流

Destroying The Graph 构图思路: 1.将所有顶点v拆成两个点, v1,v2 2.源点S与v1连边,容量为 W- 3.v2与汇点连边,容量为 W+ 4.对图中原边( a, b ), 连边 (a1,b2),容量为正无穷大 则该图的最小割(最大流)即为最小花费. 简单证明: 根据ST割集的定义,将顶点分成两个点集.所以对于原图中的边(a,b),转换成 S->a1->b2->T. 则此时路径必定存在 一条割边,因为a1->b2为无穷大,所以割边必定是 S->a1

POJ3469_Dual Core CPU(网络流/最小割=最大流/模版)----Dinic模版2.0

解题报告 题目传送门 题意: 双核CPU,n个模块,每个模块必须运行在某个CPU核心上,每个模块在cpu单核的消耗A和B,M对模块要共享数据,如果在同一个核心上不用消耗,否则需要耗费.安排N个模块,使得总耗费最小 思路: 将两个cpu核心看成源点和汇点,其他模块分别与源点汇点连线(表示每个模块可以在任意cpu上运行),m对模块分别连双向边,要使得模块只能在一个cpu上运行,就是找到一个割,源点和汇点必不联通,耗费最少就是最小割,最小割最大流原理转换成求最大流. 这题数据大,没优化TLE了,加了两

UVA - 10480 Sabotage 最小割,输出割法

UVA - 10480 Sabotage 题意:现在有n个城市,m条路,现在要把整个图分成2部分,编号1,2的城市分成在一部分中,拆开每条路都需要花费,现在问达成目标的花费最少要隔开那几条路. 题解:建图直接按给你的图建一下,然后呢跑一下最大流,我们就知道了最小割是多少,答案就是最小割了  . 现在要求输出割法.我们从s开始往前跑,如果某条正向边有流量,我们就按着这条边继续往外走,知道无法再走,把所有经历过的点都染一下色.最后看所有的边,是不是有一头是染色了,另一头没有染色,如果是,这条边就是割

hiho一下 第119周 #1398 : 网络流五&#183;最大权闭合子图 【最小割-最大流--Ford-Fulkerson 与 Dinic 算法】

#1398 : 网络流五·最大权闭合子图 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 周末,小Hi和小Ho所在的班级决定举行一些班级建设活动. 根据周内的调查结果,小Hi和小Ho一共列出了N项不同的活动(编号1..N),第i项活动能够产生a[i]的活跃值. 班级一共有M名学生(编号1..M),邀请编号为i的同学来参加班级建设活动需要消耗b[i]的活跃值. 每项活动都需要某些学生在场才能够进行,若其中有任意一个学生没有被邀请,这项活动就没有办法进行. 班级建设的活

POJ 3308 Paratroopers (二分图最小点权覆盖 -&gt; 最小割 -&gt; 最大流)

POJ 3308 Paratroopers 链接:http://poj.org/problem?id=3308 题意:有一个N*M的方阵,有L个伞兵降落在方阵上.现在要将所有的伞兵都消灭掉,可以在每行每列装一个高射炮,如果在某行(某列)装上高射炮之后,能够消灭所有落在该行(该列)的伞兵.每行每列安高射炮有费用,问如何安装能够使得费用之积最小. 思路:首先题目要求乘积最小,将乘积对e取对数,会发现就变成了求和.然后抽象出一个二分图,每一行是x部的一个点,每个点有权值,权值为费用取ln.每一列是y部

734. [网络流24题] 方格取数问题 二分图点权最大独立集/最小割/最大流

?问题描述:在一个有m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.?编程任务:对于给定的方格棋盘,按照取数要求编程找出总和最大的数.?数据输入:由文件grid.in提供输入数据.文件第1 行有2 个正整数m和n,分别表示棋盘的行数和列数.接下来的m行,每行有n个正整数,表示棋盘方格中的数. [问题分析] 二分图点权最大独立集,转化为最小割模型,从而用最大流解决. [建模方法] 首先把棋盘黑白