poj 3436 ACM Computer Factory 顶点流量限制+路径输出

http://poj.org/problem?id=3436

题意可以看vjudge里面的

 

假如a的输出结构等于b的输入结构,那么就可以连一条边。

边的容量是INF,但是点是有上限的,所以我们将点拆开,一个点变成两个点,中间有一条容量为点容量的线连接。

当然需要加上对于输入结构是0 0 0 0 ...的要连接超级源点和输出结构是 1 1 1 1 1.....的要链接超级汇点,容量依然是INF

本题使用dinic算法,我们可以使用一个m数组,记录dinic的价值变化,具体可以看代码,在有关地方都有标注

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#include<iostream>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5;
struct node {
	int to, val, nxt;
}edges[maxn];
int head[maxn], deep[maxn];
int n, p;

struct Dinic {
	int id, s, t;
	int m[200][200]; //记录 跟着一起加减
	void init(int n1,int n2) {
		id = -1;
		s = n1;
		t = n2; //s:  源点    t:汇点
		memset(head, -1, sizeof(head));
		memset(m, 0, sizeof(m));
	}
	void add_edge(int fro, int to, int val) {
		edges[++id].to = to;
		edges[id].val = val;
		edges[id].nxt = head[fro];
		head[fro] = id;
		edges[++id].to = fro;
		edges[id].val = 0;
		edges[id].nxt = head[to];
		head[to] = id;
	}
	bool bfs() { //建deep
		memset(deep, 0, sizeof(deep));
		deep[s] = 1;
		queue<int> Q;
		Q.push(s);
		while (!Q.empty()) {
			int now = Q.front();
			Q.pop();
			for (int i = head[now]; i != -1; i = edges[i].nxt) {
				int to = edges[i].to;
				if (edges[i].val && deep[to] == 0) {
					deep[to] = deep[now] + 1;
					if (to == t) return 1;
					Q.push(to);
				}
			}
		}
		return 0;
	}
	int dfs(int point , int flow) {
		if (point == t) return flow;
		int lat_cost, cost = 0;
		for (int i = head[point]; i != -1; i = edges[i].nxt) {
			int to = edges[i].to;
			if (deep[to] == deep[point] + 1 && edges[i].val) {
				lat_cost = dfs(to, min(flow - cost, edges[i].val)); // ?
				if (lat_cost > 0) {
					m[point][to] += lat_cost;
					m[to][point] -= lat_cost; //记录路径
					edges[i].val -= lat_cost;
					edges[i ^ 1].val += lat_cost;
					cost += lat_cost;
					if (flow == cost) break;
				}
			}
		}
		return cost;
	}
	void Output() { //输出路径
		int cnt = 0;
		vector<int> r;
		for (int i = 2; i <= 2*p+ 1 ; i+=2) {
			for (int j = 1; j <= 2 * p + 1 ; j+=2) {
				if (j == i - 1) continue;
				if (m[i][j]) {
					cnt++;
					//cout << i / 2 << " " << (j + 1) / 2 <<" "<< m[i][j] << endl;
					r.push_back(i / 2);
					r.push_back((j + 1) / 2);
					r.push_back(m[i][j]);
				}
			}
		}
		cout << cnt << endl;
		for (int i = 0; i < cnt; i++) {
			cout << r[3 * i] << " " << r[3 * i + 1] <<" "<< r[3 * i + 2] << endl;
		}
	}
	int dinic() {
		int ans = 0;
		while (bfs()) {
			ans += dfs(s, INF);
		}
		return ans;
	}
};
Dinic dic;
int sfro[55][15], sto[55][15], val[55];
bool Check_beg(int i) { //检查是否与超级源点链接
	for (int j = 1; j <= n; j++) {
		if (sfro[i][j]==1) {  //等于0和2都可以,等于1就退出
			return 0;
		}
	}
	return 1;
}
bool Check_end(int i) { //检查是否与超级汇点链接
	for (int j = 1; j <= n; j++) {
		if (sto[i][j] == 0) return 0;
	}
	return 1;
}
int main() {
	while (scanf("%d %d", &n, &p)!=EOF) {
		dic.init(0, 2*p + 2); //因为点要裂开,所以点的数量要乘2
		for (int i = 1; i <= p; i++) {
			scanf("%d", val + i);
			for (int j = 1; j <= n; j++) {
				scanf("%d", &sfro[i][j]);
			}
			for (int j = 1; j <= n; j++) {
				scanf("%d", &sto[i][j]);
			}
		}
		//总体应该*2  入: 2*i-1  出 2*i  汇点2*p+2
		for (int i = 1; i <= p; i++) {
			dic.add_edge(2 * i - 1, 2 * i, val[i]);
			if (Check_beg(i)) {
				dic.add_edge(0, 2*i-1, INF);
			}
			if (Check_end(i)) {
				dic.add_edge(2*i, 2*p + 2, INF);
			}
			for (int j = 1; j <= p; j++) {
				if (i == j) continue;
				int ok = 1;
				for (int k = 1; k <= n; k++) {
					if (!(sto[i][k] == sfro[j][k] || sfro[j][k] == 2)) {
						ok = 0;
						break;
					}
				}
				if (ok == 1) { //建边
					dic.add_edge(2*i, 2*j-1, INF);
				}
			}
		}
		cout << dic.dinic() << " ";
		dic.Output();
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值