题目描述
W 教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业性实验而获取利润。现已确定了一个可供选择的实验集合E={E1,E2,…,Em},和进行这些实验需要使用的全部仪器的集合I={I1,I2,…In}。实验Ej需要用到的仪器是I的子集RjÍI。配置仪器Ik的费用为ck美元。实验Ej的赞助商已同意为该实验结果支付pj美元。W教授的任务是找出一个有效算法,确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大。这里净收益是指进行实验所获得的全部收入与配置仪器的全部费用的差额。
对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划。
输入输出格式
输入格式:
第1行有2 个正整数m和n。m是实验数,n是仪器数。接下来的m 行,每行是一个实验的有关数据。第一个数赞助商同意支付该实验的费用;接着是该实验需要用到的若干仪器的编号。最后一行的n个数是配置每个仪器的费用。
输出格式:
第1 行是实验编号;第2行是仪器编号;最后一行是净收益。
输入输出样例
输出样例#1:
1 2 1 2 3 17
准备开始入门网络流,尽快的刷完网络流24题吧。
这题其实是一个最大流最小割定理的理解,
设所有没有选择的实验项目的资金和为a,所有使用了的实验仪器的资金和为b;
我们这个就是要想办法将a+b变得尽可能得小;
于是我们想办法建图,
将实验和仪器组成一个二分图;
创建源点和汇点,源点连向所有实验,容量为c[i],所有仪器连向汇点,容量为p[i];
实验和一起之间为权值为INF,源点和实验的权值为经费,汇点和仪器的权值为价格;
使得a+b尽可能得小,就是删除刚刚建立的弧,一旦删去了这些弧,整个网络将是不连通的。
然后就是跑一个最大流。
1 #include <cstdio> 2 #include <algorithm> 3 #include <vector> 4 #include <queue> 5 #include <cstring> 6 #include <string> 7 #include <map> 8 using namespace std; 9 const int maxn = 2e5 + 10; 10 const int INF = 1e9 + 10; 11 typedef long long LL; 12 struct node { 13 int from, to, cap, flow; 14 }; 15 struct Dinic { 16 int n, m, s, t; 17 vector<node>nodes; 18 vector<int>g[maxn]; 19 int vis[maxn]; 20 int d[maxn]; 21 int cur[maxn]; 22 void clearall(int n) { 23 for (int i = 0 ; i < n ; i++) g[i].clear(); 24 nodes.clear(); 25 } 26 void clearflow() { 27 int len = nodes.size(); 28 for (int i = 0 ; i < len ; i++) nodes[i].flow = 0; 29 } 30 void add(int from, int to, int cap) { 31 nodes.push_back((node) { 32 from, to, cap, 0 33 }); 34 nodes.push_back((node) { 35 to, from, 0, 0 36 }); 37 m = nodes.size(); 38 g[from].push_back(m - 2); 39 g[to].push_back(m - 1); 40 } 41 bool bfs() { 42 memset(vis, 0, sizeof(vis)); 43 queue<int>q; 44 q.push(s); 45 d[s] = 0; 46 vis[s] = 1; 47 while(!q.empty()) { 48 int x = q.front(); 49 q.pop(); 50 int len = g[x].size(); 51 for (int i = 0 ; i < len ; i++) { 52 node &e = nodes[g[x][i]]; 53 if (!vis[e.to] && e.cap > e.flow ) { 54 vis[e.to] = 1; 55 d[e.to] = d[x] + 1; 56 q.push(e.to); 57 } 58 } 59 } 60 return vis[t]; 61 } 62 int dfs(int x, int a) { 63 if (x == t || a == 0) return a; 64 int flow = 0, f, len = g[x].size(); 65 for (int &i = cur[x] ; i < len ; i++) { 66 node & e = nodes[g[x][i]]; 67 if (d[x] + 1 == d[e.to] && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0 ) { 68 e.flow += f; 69 nodes[g[x][i] ^ 1].flow -= f; 70 flow += f; 71 a -= f; 72 if (a == 0) break; 73 } 74 } 75 return flow; 76 } 77 int maxflow(int a, int b) { 78 s = a; 79 t = b; 80 int flow = 0; 81 while(bfs()) { 82 memset(cur, 0, sizeof(cur)); 83 flow += dfs(s, INF); 84 } 85 return flow; 86 } 87 vector<int>mincut() { 88 vector<int>ans; 89 int len = nodes.size(); 90 for (int i = 0 ; i < len ; i++) { 91 node & e = nodes[i]; 92 if ( vis[e.from] && !vis[e.to] && e.cap > 0 ) ans.push_back(i); 93 } 94 return ans; 95 } 96 void reduce() { 97 int len = nodes.size(); 98 for (int i = 0 ; i < len ; i++) nodes[i].cap -= nodes[i].flow; 99 } 100 void display(int p, int q) { 101 int qq[maxn]; 102 int cnt = 0; 103 for(int i = 1; i <= q; i++)if(vis[i])qq[++cnt] = i; 104 for(int i = 1; i < cnt; i++)printf("%d ", qq[i]); 105 printf("%d ", qq[cnt]); 106 memset(qq, 0, sizeof(qq)); 107 cnt = 0; 108 for(int i = 1; i <= p; i++)if(vis[i + q])qq[++cnt] = i; 109 for(int i = 1; i < cnt; i++)printf("%d ", qq[i]); 110 printf("%d ", qq[cnt]); 111 } 112 } f; 113 int main() { 114 int n, m, sum = 0; 115 scanf("%d%d", &m, &n); 116 for (int i = 1 ; i <= m ; i++) { 117 int x; 118 scanf("%d", &x); 119 sum += x; 120 f.add(0, i, x); 121 char ch; 122 int temp = 0; 123 ch = getchar(); 124 while((ch = getchar()) != ' ') { 125 x = ch - '0'; 126 while((ch = getchar()) && ch >= '0' && ch <= '9') 127 x = x * 10 + ch - '0'; 128 f.add(i, x + m, INF); 129 if(ch == ' ')break; 130 } 131 } 132 for (int i = 1 ; i <= n ; i++) { 133 int x; 134 scanf("%d", &x); 135 f.add(m + i, m + n + 1, x); 136 } 137 int ret = f.maxflow(0, n + m + 1); 138 f.display(n, m); 139 printf("%d ", sum - ret); 140 return 0; 141 }