Poj3436——ACM Computer Factory(最大流)

题意:

流水线上有N台机器装电脑,电脑有P个部件组成,每台机器有三个参数,产量,输入规格,输出规格;输入规格中0表示改部件不能有,1表示必须有,2无所谓;输出规格中0表示该部件没有,1表示有。问如何安排流水线使电脑产量最高。

思路:

每个机器都是一个结点,点上有容量。拆点,中间连一条边,容量设为产量。然后根据输入规格和输出规格建立网络。跑最大流,有流量的边就是方案中包含的边。

#include 
#include 
#include 
#include 
#include 
const int INF = 0x3f3f3f3f;
const int maxn = 100 + 5;
using namespace std;

int G1[maxn][25];
int P,N;
// 图
struct Edge{
	int u,v,cap,flow;
	Edge(int a, int b, int c, int d):u(a),v(b),cap(c),flow(d){}
};
vector edges;
vector G[maxn];
void init(int n){
	for(int i = 0; i < n; ++i) G[i].clear();
	edges.clear();
}
void addEdge(int u, int v, int w){
	edges.push_back(Edge(u, v, w, 0));
	edges.push_back(Edge(v, u, 0, 0));
	int m = edges.size();
	G[u].push_back(m-2);
	G[v].push_back(m-1);
}

int dis[maxn];	// 分层的编号 
int cur[maxn]; // 当前弧,重要优化!!! 
// 分层 
bool bfs(int s, int t){
	memset(dis, -1, sizeof(dis));
	dis[s] = 0;
	queue Q;
	Q.push(s);
	while(!Q.empty()){
		int x = Q.front(); Q.pop();
		for(int i = 0; i < G[x].size(); ++i){
			Edge e = edges[G[x][i]];
			if(dis[e.v] == -1&&e.cap > e.flow){
				dis[e.v] = dis[x] + 1;
				Q.push(e.v);
			}
		}
	}
	return dis[t] != -1;
}

int dfs(int s, int t, int cur_flow){
	if(s == t||cur_flow == 0) return cur_flow;
	int ans = 0;
	for(int& i = cur[s]; i < G[s].size(); ++i){
		int c = G[s][i];
		Edge e = edges[c];
		if(dis[e.v] == dis[s] + 1&&e.cap > e.flow){
			int a2 = min(cur_flow, e.cap-e.flow);
			int w = dfs(e.v, t, a2);
			edges[c].flow += w;
			edges[c^1].flow -= w; 
			cur_flow -= w;
			ans += w;
			if(cur_flow <= 0) break;
		}
	}
	return ans;
}

// 最大流 
int Dinic(int s, int t){
	int ans = 0;
	while(bfs(s,t)){
		memset(cur, 0, sizeof(cur));
		ans += dfs(s,t,INF);
	}
	return ans;	
}

struct node{
	int a,b,c;
	node(int a, int b, int c):a(a),b(b),c(c){}
};
vector ans;

int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%d%d",&P,&N) == 2){
    	init(2*N+2);
    	
    	for(int i = 1; i <= N; ++i){
    		int c; scanf("%d",&c); addEdge(i, i+N, c);
    		G1[i][0] = G1[i][2*P+1] = 0;
    		for(int j = 1; j <= P; ++j){
				int t; scanf("%d",&t);
				G1[i][j] = t;
				if(1 == t) ++G1[i][0];
			}
			for(int j = P+1; j <= 2*P; ++j){
				int t; scanf("%d",&t);
				G1[i][j] = t;
				if(0 == t) ++G1[i][2*P+1];
			}
		}
		
		// 建边
		int s = 0, t = 2*N+1;
		for(int i = 1; i <= N; ++i){
			if(G1[i][0] == 0) addEdge(s, i, INF);
			if(G1[i][2*P+1] == 0) addEdge(i+N, t, INF);
			for(int j = 1; j < i; ++j){
				bool flag = true;
				for(int k = P+1; flag&&k <= 2*P; ++k)
					if(G1[i][k] + G1[j][k-P] == 1) flag = false;
				if(flag) addEdge(i+N, j, INF);
			
				flag = true;
				for(int k = P+1; flag&&k <= 2*P; ++k)
					if(G1[j][k] + G1[i][k-P] == 1) flag = false;
				if(flag) addEdge(j+N, i, INF);
			}
		}
		
		printf("%d", Dinic(s, t));
		
		ans.clear();
		for(int i = 0; i < edges.size(); ++i){
			Edge& e = edges[i];
			if(e.u == s||e.v == t||e.flow <= 0||e.v - e.u == N) continue;
			int u = e.u > N? e.u-N : e.u;
			ans.push_back(node(u, e.v, e.flow));
		}
		printf(" %d\n", ans.size());
		for(int i = 0; i < ans.size(); ++i) printf("%d %d %d\n",ans[i].a, ans[i].b, ans[i].c); 
	}
    
    fclose(stdin);
	return 0;
}

你可能感兴趣的:(网络流)