[网络流24题] 太空飞行计划 (最大权闭合子图---网络最大流)

727. [网络流24题] 太空飞行计划
★★☆   输入文件:shuttle.in   输出文件:shuttle.out   简单对比
时间限制:1 s   内存限制:128 MB

【问题描述】
W 教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业性实验而获取利润。现已确定了一个可供选择的实验集合E={E1,E2,…,Em},和进行这些实验需要使用的全部仪器的集合I={ I1, I2,…,In }。实验Ej 需要用到的仪器是I的子集Rj∈I。配置仪器Ik 的费用为ck 美元。实验Ej 的赞助商已同意为该实验结果支付pj 美元。W教授的任务是找出一个有效算法,确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大。这里净收益是指进行实验所获得的全部收入与配置仪器的全部费用的差额。
【编程任务】
对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划。
【数据输入】
第1行有2个正整数m和n(m,n <= 100)。m是实验数,n是仪器数。接下来的m行,每行是一个实验的有关数据。第一个数赞助商同意支付该实验的费用;接着是该实验需要用到的若干仪器的编号。最后一行的n个数是配置每个仪器的费用。
【结果输出】
第1行是实验编号;第2行是仪器编号;最后一行是净收益。
【输入文件示例】shuttle.in

2 3
10 1 2
25 2 3
5 6 7

【输出文件示例】shuttle.out

1 2
1 2 3
17

 

算法讨论:

最大权闭合子图的裸题。

要求输出方案的话,就是与S点相连的边,直接DFS一遍就好了,注意走剩余流量大于0的边。

贴一个不错的学习网址:http://www.cnblogs.com/wuyiqi/archive/2012/03/12/2391960.html

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <vector>

using namespace std;
const int N = 200 + 5;
const int oo = 0x3f3f3f3f;

int n, m, S, T, sum = 0;
int cost[105];
bool ans[205];
char ss[10005];

struct data {
	int pay;
	vector <int> number;
}ex[105];

struct Edge {
	int from, to, cap, flow;
	Edge(int u = 0, int v = 0, int cap = 0, int flow = 0) :
		from(u), to(v), cap(cap), flow(flow) {}
};

struct Dinic {
	int nn, mm, s, t;
	int dis[N], cur[N], que[N * 10];
	bool vis[N];
	vector <Edge> edges;
	vector <int> G[N];

	void add(int from, int to, int cap) {
		edges.push_back(Edge(from, to, cap, 0));
		edges.push_back(Edge(to, from, 0, 0));
		mm = edges.size();
		G[from].push_back(mm - 2);
		G[to].push_back(mm - 1);
	}
	
	bool bfs() {
		int head = 1, tail = 1;
		memset(vis, false, sizeof vis);
		dis[s] = 0; que[head] = s; vis[s] = true;
		while(head <= tail) {
			int x = que[head];
			for(int i = 0; i < (signed) G[x].size(); ++ i) {
				Edge &e = edges[G[x][i]];
				if(!vis[e.to] && e.cap > e.flow) {
					dis[e.to] = dis[x] + 1;
					vis[e.to] = true;
					que[++ tail] = e.to;
				}
			}
			++ head;
		}
		return vis[t];
	}
	
	int dfs(int x, int a) {
		if(x == t || a == 0) return a;
		int flw = 0, f;
		for(int &i = cur[x]; i < (signed) G[x].size(); ++ i) {
			Edge &e = edges[G[x][i]];
			if(dis[e.to] == dis[x] + 1 && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0) {
				e.flow += f; edges[G[x][i] ^ 1].flow -= f;
				flw += f; a -= f;
				if(a == 0) break;
			}
		}
		return flw;
	}
	
	int mx(int s, int t) {
		this->s = s; this->t = t;
		int flw = 0;
		while(bfs()) {
			memset(cur, 0, sizeof cur);
			flw += dfs(s, oo);
		}
		return flw;
	}
	
	void dfs(int x) {
		for(int i = 0; i < G[x].size(); ++ i) {
			Edge e = edges[G[x][i]];
			if(e.cap - e.flow > 0 && !ans[e.to]) {
				ans[e.to] = true;
				dfs(e.to);
			}
		}
	}
	
	void getans() {
		dfs(S);
		for(int i = 1; i <= m; ++ i) if(ans[i]) printf("%d ", i);
		puts("");
		for(int i = m + 1; i < T; ++ i) if(ans[i]) printf("%d ", i - m);
		puts("");
	}
}net;


#define stone_e

int main() {
#ifndef stone_
	freopen("shuttle.in", "r", stdin);
	freopen("shuttle.out", "w", stdout);
#endif

	int x; char ch;
	scanf("%d%d", &m, &n);
	S = 0, T = n + m + 1;
	getchar();
	for(int i = 1; i <= m; ++ i) {
		scanf("%d", &ex[i].pay);
		while(scanf("%d%c", &x, &ch)) {
			ex[i].number.push_back(x);
			if(ch == '\r') break;
		}
	}
	for(int i = 1; i <= n; ++ i) scanf("%d", &cost[i]);
	for(int i = 1; i <= m; ++ i) {
		net.add(S, i, ex[i].pay);
		sum += ex[i].pay;
		for(int j = 0; j < ex[i].number.size(); ++ j)
		  net.add(i, ex[i].number[j] + m, oo);
	}
	net.nn = n + m + 1;
	for(int i = 1; i <= n; ++ i) net.add(i + m, T, cost[i]);
	sum = sum - net.mx(S, T);
	net.getans();
	printf("%d\n", sum);
	
#ifndef stone_
	fclose(stdin); fclose(stdout);
#endif
	return 0;
}

 

posted @ 2016-04-19 12:06  漫步者。!~  阅读(285)  评论(0编辑  收藏  举报