poj_3436 网络最大流

题目大意

生产电脑的工厂将一台电脑分成P个部件来进行流水线生产组装,有N个生产车间,每个车间可以将一个半成品电脑添加某些部件,使之成为另一个半成品电脑或者成为一台完好的电脑,且每个车间有一个效率,即在单位时间内可以将K个半成品组装为另外K个半成品或者完好的电脑。每个车间在组装完成之后,都将组装后的半成品送到另外一个车间,成品直接送到成品区。 
    现在给出这N个车间的组装原部件集合以及组装后的部件集合(其中 in[1,2,3...p]中 in[i]表示第i种组装元部件,out[1,2,3...p]中out[i]表示第i种组装后的部件。且in[i] = 0表示元部件集合中必须没有第i种部件,in[i]=1表示元部件集合中必须有第i种部件,in[i] = 2表示元部件集合中第i种部件可有可无;out[i]=0表示组装后的部件集合中没有第i种部件,out[i]=1表示组装后的集合中有第i种部件),以及组装效率。求怎样合理的分配N个车间之间的流量,使得组装效率最大。

题目分析

在本题中的最大效率,可以视为各个车间构成的网络图的最大流量。那么,如何构造网络流图求出最大流量呢? 
    首先考虑将每个车间视为一个节点,若车间A的组装后的部件集合可以被车间B接受,那么单向连接车间A和B。但是,若车间A连接了车间B和车间C,那么A->B和A->C之间的路径容量无法控制。所以这种建图方式不好。 
    再考虑将每个车间拆分为两个节点,一个入节点,表示车间的组装原部件集合,一个出节点,表示车间组装后的部件集合,在入节点和出节点之间用一条容量为K的路径连接起来。若车间A的组装后部件集合可以被车间B的组装原部件集合所接受,那么连接车间A的出节点和车间B的入节点,同时,容量设为无穷大,这是因为车间的效率受其原部件-->组装后部件的组装效率决定,即车间的入节点到出节点的容量决定。 
    在构造好的图上从源点到汇点找最大流量,即为最大效率。

实现

#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
#define MAX_NODE 150
#define MAX_EDGE_NUM 300
#define INFINITE 1 << 25
#define min(a, b) a<b? a:b
struct Edge{
	int from;
	int to;
	int w;
	int next;
	int rev;
	bool operator == (const pair<int, int>& p){
		return from == p.first && to == p.second;
	}
};
Edge gEdges[MAX_EDGE_NUM];

int gEdgeCount;
int gFlow[MAX_NODE][MAX_NODE];
int gGap[MAX_NODE];
int gDist[MAX_NODE];
int gHead[MAX_NODE];
int gPre[MAX_NODE];
int gPath[MAX_NODE];

int gSource, gDestination;
void InsertEdge(int u, int v, int w){
	Edge* it = find(gEdges, gEdges + gEdgeCount, pair<int, int>(u, v));
	if (it != gEdges + gEdgeCount){
		it->w = w;
	}
	else{
		int e1 = gEdgeCount;
		gEdges[e1].from = u;
		gEdges[e1].to = v;
		gEdges[e1].w = w;
		gEdges[e1].next = gHead[u];
		gHead[u] = e1;

		gEdgeCount++;
		int e2 = gEdgeCount;
		gEdges[e2].from = v;
		gEdges[e2].to = u;
		gEdges[e2].w = 0;
		gEdges[e2].next = gHead[v];
		gHead[v] = e2;

		gEdges[e1].rev = e2;
		gEdges[e2].rev = e1;
		gEdgeCount++;
	}
}

void Bfs(){
	memset(gGap, 0, sizeof(gGap));
	memset(gDist, -1, sizeof(gDist));
	gGap[0] = 1;
	gDist[gDestination] = 0;
	queue<int>Q;
	Q.push(gDestination);
	while (!Q.empty()){
		int n = Q.front();
		Q.pop();
		for (int e = gHead[n]; e != -1; e = gEdges[e].next){
			int v = gEdges[e].to;
			if (gDist[v] >= 0)
				continue;
			gDist[v] = gDist[n] + 1;
			gGap[gDist[v]] ++;
			Q.push(v);
		}
	}
}

int ISAP(int n){ // n为节点的数目
	Bfs();
	int u = gSource;
	int e, d;
	int ans = 0;
	while (gDist[gSource] <= n){
		if (u == gDestination){ //增广
			int min_flow = INFINITE;
			for (e = gPath[u]; u != gSource; e = gPath[u = gPre[u]]){ //注意,先u = gPre[u], 再取 e = gPath[u]
				min_flow = min(min_flow, gEdges[e].w);
			}
			u = gDestination;
			for (e = gPath[u]; u != gSource; e = gPath[u = gPre[u]]){
				gEdges[e].w -= min_flow;
				gEdges[gEdges[e].rev].w += min_flow;

				gFlow[gPre[u]][u] += min_flow;
			}
			ans += min_flow;
		}
		for (e = gHead[u]; e != -1; e = gEdges[e].next){
			if (gEdges[e].w > 0 && gDist[u] == gDist[gEdges[e].to] + 1)
				break;
		}
		if (e >= 0){ //向前推进
			gPre[gEdges[e].to] = u; //前一个点
			gPath[gEdges[e].to] = e;//该点连接的前一个边
			u = gEdges[e].to;
		}
		else{
			d = n;
			for (e = gHead[u]; e != -1; e = gEdges[e].next){
				if (gEdges[e].w > 0)	//需要能够走通才行!!
					d = min(d, gDist[gEdges[e].to]);
			}
			if (--gGap[gDist[u]] == 0) //gap优化
				break;

			gDist[u] = d+1;		//重标号

			++gGap[gDist[u]];	//更新 gap!!
			if (u != gSource)
				u = gPre[u];//回溯
		}
	}
	return ans;
}

struct Node{
	int id;
	int p;
	int component[12];
	bool CanConnect(const Node& node){
		for (int i = 0; i < p; i++){
			if (component[i] == 0 && node.component[i] == 1 || component[i] == 1 && node.component[i] == 0)
				return false;
		}
		return true;
	}
};
Node gNodes[MAX_NODE];

void BuildGraph(int n){
	for (int i = 2; i <= n + 1; i++){
		if (gNodes[1].CanConnect(gNodes[i]))
			InsertEdge(1, i, INFINITE);
	}
	for (int i = n+2; i <= 2*n + 1; i++){
		for (int j = 2; j <= n + 1; j++){
			if (j + n != i && gNodes[i].CanConnect(gNodes[j]))
				InsertEdge(i, j, INFINITE);

		}
	}
	for (int i = n + 2; i <= 2 * n + 1; i++){
		if (gNodes[i].CanConnect(gNodes[2*n+2]))
			InsertEdge(i, 2*n+2, INFINITE);
	}
}
void print_graph(int n){
	for (int u = 1; u <= n; u++){
		printf("node %d links to ", u);
		for (int e = gHead[u]; e != -1; e = gEdges[e].next)
			printf("%d(flow = %d) ", gEdges[e].to, gEdges[e].w);
		printf("\n");
	}
}

int main(){
	int p, n, w, u, v;
	while (scanf("%d %d", &p, &n) != EOF){

		memset(gFlow, 0, sizeof(gFlow));
		memset(gHead, -1, sizeof(gHead));
		gEdgeCount = 0;

		int node_id = 1;			//构造源点
		gNodes[node_id].p = p;
		for (int i = 0; i < p; i++){
			gNodes[node_id].component[i] = 0;
		}
		node_id++;

		for (int i = 0; i < n; i++){
			scanf("%d", &w);
			u = node_id;
			gNodes[u].p = p;
			for (int k = 0; k < p; k++){
				scanf("%d", &gNodes[u].component[k]);
			}

			v = node_id + n;
			gNodes[v].p = p;
			for (int k = 0; k < p; k++){
				scanf("%d", &gNodes[v].component[k]);
			}

			node_id++;
			InsertEdge(u, v, w);
		}
		node_id = 2 * n + 2;
		gNodes[node_id].p = p;
		for (int i = 0; i < p; i++){	//构造汇点
			gNodes[node_id].component[i] = 1;
		}
		gSource = 1; gDestination = 2 * n + 2;
		BuildGraph(n);
//		print_graph(2 * n + 2);
		int result = ISAP(2 * n + 2);
		printf("%d", result);
		int count = 0;
		vector<pair<int, int> > edge_vec;
		for (int i = n + 2; i <= 2 * n + 1; i++){
			for (int j = 2; j <= n + 1; j++){
				if (i != j + n && gFlow[i][j] > 0){
					count++;
					edge_vec.push_back(pair<int, int>(i, j));
				}
			}
		}
		printf(" %d\n", count);
		for (int k = 0; k < count; k ++){
			int i = edge_vec[k].first;
			int j = edge_vec[k].second;
			printf("%d %d %d\n", i - n - 1, j - 1, gFlow[i][j]);
		}
	}
	return 0;
}
时间: 2024-10-26 11:57:57

poj_3436 网络最大流的相关文章

算法模板——Dinic网络最大流 2

实现功能:同Dinic网络最大流 1 这个新的想法源于Dinic费用流算法... 在费用流算法里面,每次处理一条最短路,是通过spfa的过程中就记录下来,然后顺藤摸瓜处理一路 于是在这个里面我的最大流也采用这种模式,这样子有效避免的递归,防止了爆栈么么哒 1 type 2 point=^node; 3 node=record 4 g,w:longint; 5 next,anti:point; 6 end; 7 var 8 i,j,k,l,m,n,s,t,flow:longint; 9 a,e:a

POJ--3308--Paratroopers【Dinic】二分图顶点覆盖+网络最大流

链接:http://poj.org/problem?id=3308 题意:未来世界火星人要入侵地球,他们要派一些伞兵来摧毁地球的兵工厂,兵工厂可以视为一个m*n的矩阵,现在知道了他们每个伞兵的降落位置.为了粉碎火星人的阴谋,我们需要在某行或某列来架一个机关枪来消灭一整行或一整列的火星人,但是在这需要一定的花费,告诉每行及每列架机关枪的花费,总花费是每行及每列的花费相乘.求使得火星人全部被消灭的最小花费. 思路:需要消灭所有敌人,是二分图最小点权覆盖问题,要覆盖所有的边并使花费最小,即求最小割,根

POJ--1087--A Plug for UNIX【Dinic】网络最大流

链接:http://poj.org/problem?id=1087 题意:提供n种插座,每种插座只有一个,有m个设备需要使用插座,告诉你设备名称以及使用的插座类型,有k种转换器,可以把某种插座类型转为另一种,可以嵌套使用,比如有设备需使用第4种插座,现在只有第一种插座,但是有两个转换器,1→3和3→4,则通过这两个转换器设备可以充电.每种转换器有无数个.现告诉你相应信息,求至少有多少个设备无法使用插座. 网络最大流单源点单汇点,是一道基础题,图建好就能套模板了.关键是图怎么建. 还是自己设一个源

POJ 3281 Dining(网络最大流)

http://poj.org/problem?id=3281 Dining Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 9121   Accepted: 4199 Description Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she will consume no others.

POJ 3436 ACM Computer Factory(网络最大流)

http://poj.org/problem?id=3436 ACM Computer Factory Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5286   Accepted: 1813   Special Judge Description As you know, all the computers used for ACM contests must be identical, so the particip

windows使用libvlc进行网络串流遇到的一些问题及解决方法

先贴代码, #define WIFI_W 640#define WIFI_H 480 struct ctx { uchar* frame; }; class CConnectWIFI { public: CConnectWIFI(void); void Init(HWND hWnd); libvlc_instance_t* m_vlcInst; libvlc_media_player_t* m_vlcMplay; libvlc_media_t* m_vlcMedia; struct ctx co

P3376 【模板】网络最大流(70)

题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行包含三个正整数ui.vi.wi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi) 输出格式: 一行,包含一个正整数,即为该网络的最大流. 输入输出样例 输入样例#1: 4 5 4 3 4 2 30 4 3 20 2 3 20 2 1 30 1 3 40 输出样例#1: 50

HDU 3549 网络最大流再试

http://acm.hdu.edu.cn/showproblem.php?pid=3549 同样的网络最大流 T了好几次原因是用了cout,改成printf就A了 还有HDU oj的编译器也不支持以下的写法 G[from].push_back((edge){to,cap,G[to].size()}); G[to].push_back((edge){from,0,G[from].size() - 1}); #include<iostream> #include<cstdio> #i

网络最大流算法

网络最大流是指在一个网络流图中可以从源点流到汇点的最大的流量.求解网络最大流的常用算法可以分为增广路径算法和预推进算法.其中,预推进算法的理论复杂度优于增广路径算法,但是编码复杂度过高,且效率优势在很多时候并不是很明显,因此,经常使用的算法为增广路径算法.     增广路径算法主要有Fold-Fulkerson算法,Edmonds-Karp算法,Dinic算法,ISAP算法.其中,Fold-Fulkerson 是最基本的增广路径思想,不能算作严格的算法实现. 增广路径     增广路径算法的思想