网络流24题——太空飞行计划

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/GYH0730/article/details/82350318

题目链接:https://www.luogu.org/problemnew/show/P2762

【问题分析】

最大权闭合图问题,可以转化成最小割问题,进而用最大流解决。

【建模方法】

把每个实验看作二分图X集合中的顶点,每个设备看作二分图Y集合中的顶点,增加源S和汇T。
1、从S向每个Xi连接一条容量为该点收入的有向边。
2、从Yi向T连接一条容量为该点支出的有向边。
3、如果一个实验i需要设备j,连接一条从Xi到Yj容量为无穷大的有向边。

统计出所有实验的收入只和Total,求网络最大流Maxflow,最大收益就是Total-Maxflow。对应的解就是最小割划分出的S集合中的点,也就是最后一次增广找到阻塞流时能从S访问到的顶点。

【建模分析】

定义一个割划分出的S集合为一个解,那么割集的容量之和就是(未被选的A集合中的顶点的权值 + 被选的B集合中的顶点的权值),记为Cut。A集合中所有顶点的权值之和记为Total,那么Total - Cut就是(被选的A集合中的顶点的权值 - 被选的B集合中的顶点的权值),即为我们的目标函数,记为A。要想最大化目标函数A,就要尽可能使Cut小,Total是固定值,所以目标函数A取得最大值的时候,Cut最小,即为最小割。

该问题的一般模型为最大权闭合图,相关讨论见《最小割模型在信息学竞赛中的应用》作者胡伯涛。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200;
const int MAXM = 2000;
const int INF = 0x3f3f3f3f;
struct Edge1
{
	int from,to,cap,flow;
};
struct Dinic
{
	int n,m,s,t;
	vector<Edge1> edges;
	vector<int> G[MAXN];
	bool vis[MAXN];
	int d[MAXN];
	int cur[MAXN];
	void init(int n)
	{
		this -> n = n;
		for(int i = 0; i <= n + 1; i++){
			G[i].clear();
		}
		edges.clear();
	}
	void AddEdge(int from,int to,int cap)
	{
		edges.push_back((Edge1){from,to,cap,0});
		edges.push_back((Edge1){to,from,0,0});
		m = edges.size();
		G[from].push_back(m - 2);
		G[to].push_back(m - 1);
	}
	bool BFS()
	{
		memset(vis,0,sizeof(vis));
		memset(d,0,sizeof(d));
		queue<int> Q;
		Q.push(s);
		d[s] = 0;
		vis[s] = 1;
		while(!Q.empty()) {
			int x = Q.front();
			Q.pop();
			for(int i = 0; i < G[x].size(); i++) {
				Edge1& e = edges[G[x][i]];
				if(!vis[e.to] && e.cap > e.flow) {
					vis[e.to] = 1;
					d[e.to] = d[x] + 1;
					Q.push(e.to);
				}
			}
		}
		return vis[t];
	}
	int DFS(int x,int a)
	{
		if(x == t || a == 0) return a;
		int flow = 0,f;
		for(int& i = cur[x]; i < G[x].size(); i++) {
			Edge1& e = edges[G[x][i]];
			if(d[x] + 1 == d[e.to] && (f = DFS(e.to,min(a,e.cap - e.flow))) > 0) {
				e.flow += f;
				edges[G[x][i] ^ 1].flow -= f;
				flow += f;
				a -= f;
				if(a == 0) break;
			}
		}
		return flow;
	}
	int Maxflow(int s,int t) {
		this -> s = s,this -> t = t;
		int flow = 0;
		while(BFS()) {
			memset(cur,0,sizeof(cur));
			flow += DFS(s,INF);
		}
		return flow;
	}
}din;
int main(void)
{
    int m,n,temp,total = 0;
    int ans;
    char c;
    scanf("%d %d",&m,&n);
    int S = 0,T = n + m + 1;
    din.init(n + m + 2);
    for(int i = 1; i <= m; i++) {
        scanf("%d",&temp);
        din.AddEdge(S,i,temp);
        total += temp;
        while(1) {
            c = getchar();
            if(c == '\n') break;
            scanf("%d",&temp);
            din.AddEdge(i,temp + m,INF);
        }
    }
    for(int i = 1; i <= n; i++) {
        scanf("%d",&temp);
        din.AddEdge(i + m,T,temp);
    }
    ans = total - din.Maxflow(S,T);
    for(int i = 1; i <= m; i++) {
        if(din.d[i]) printf("%d ",i);
    }
    printf("\n");
    for(int i = m + 1; i <= n + m; i++) {
        if(din.d[i]) printf("%d ",i - m);
    }
    cout << endl;
    cout << ans << endl;
    return 0;
}
/*
2 3
10 1 2
25 2 3
5 6 7
*/

猜你喜欢

转载自blog.csdn.net/GYH0730/article/details/82350318