题目链接: POJ - 3436
题目大意
工厂生产电脑, 有n台机器, p种原料
每台机器有一个效率q(每小时生产数量);
一个输入原料数组in[p], 其中in[i]=0代表不能有原料i, =1代表一定要有原料i, =2表示可以有也可以没有
一个输出产品数组out[p], out[i]=0代表不输出产品i, =1代表输出
其中输入原料数组全为0或2的(就是不需要输入原料的机器)为源点
输出产品全为1的就是汇点(生产出了最终产品)
输出最高效率(每小时生产电脑数), 和所有路径
思路
建图求最大流
建图方法:
设置一个超级源点S和一个超级汇点
超级源点向所有源点连一条容量为INF的边
所有汇点想超级汇点连一条容量为INF的边将每个机器i拆分成两个节点i和i+n, 连一条容量为这台机器效率的边
如果机器i的输出与机器j的输入匹配, 连一条i+n向j, 容量为inf的边
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
const int INF = 0X3F3F3F3F, MAXV = 200;
struct edge
{
int to, cap, rev, flow;
edge(int To, int Cap, int Rev, int Flow)
:to(To), cap(Cap), rev(Rev), flow(Flow){}
};
vector<edge> G[MAXV];
int iter[MAXV];
int level[MAXV];
int S, T;
int p, n;
void add_edge(int from, int to, int cap)
{
G[from].push_back(edge(to, cap, int(G[to].size()), 0));
G[to].push_back(edge(from, 0, int(G[from].size()-1), 0));
}
bool bfs()
{
memset(level, -1, sizeof(level));
queue<int> que;
level[S] = 0;
que.push(S);
while(!que.empty())
{
int v = que.front(); que.pop();
for(int i=0; i<(int)G[v].size(); ++i)
{
edge & e = G[v][i];
if(level[e.to]<0 && e.cap > e.flow)
{
level[e.to] = level[v] + 1;
que.push(e.to);
}
}
}
return level[T] != -1;
}
int dfs(int v, int f)
{
if(v == T) return f;
for(int &i=iter[v]; i<(int)G[v].size(); ++i)
{
edge &e = G[v][i];
if(e.cap>e.flow && level[e.to]>level[v])
{
int d = dfs(e.to, min(f, e.cap-e.flow));
if(d)
{
e.flow += d;
G[e.to][e.rev].flow -= d;
return d;
}
}
}
return 0;
}
int max_flow()
{
int flow = 0;
while(bfs())
{
memset(iter, 0, sizeof(iter));
int f;
while((f=dfs(S, INF))) flow += f;
}
return flow;
}
struct machine
{
int w, in[15], out[15];
}ma[70];
int q, in, out, x;
int cnt, path[1000][3];
int main()
{
while(scanf("%d%d", &p, &n) == 2)
{
S = 0;
T = 2*n+1;
for(int i=1; i<=n; ++i)
{
scanf("%d", &q);
ma[i].w = q;
bool flag = 1;
for(int j=0; j<p; ++j)
{
scanf("%d", &ma[i].in[j]);
if(ma[i].in[j] == 1) flag = 0;
}
if(flag) add_edge(S, i, INF);
flag = 1;
for(int j=0; j<p; ++j)
{
scanf("%d", &ma[i].out[j]);
if(ma[i].out[j] == 0) flag = 0;
}
if(flag) add_edge(i+n, T, INF);
}
for(int i=1; i<=n; ++i)
{
add_edge(i, i+n, ma[i].w);
for(int j=1; j<=n; ++j)
{
if(i==j) continue;
bool flag = 1;
for(int k=0; k<p; ++k)
{
if(ma[j].in[k]!=2 && ma[i].out[k]!=ma[j].in[k])
{
flag = 0;
break;
}
}
if(flag) add_edge(i+n, j, INF);
}
}
int flow = max_flow();
cnt = 0;
for(int i=n+1; i<T; ++i)
{
for(int j=0; j<(int)G[i].size(); ++j)
{
edge &e = G[i][j];
if(e.flow > 0 && e.to <= n)
{
path[cnt][0] = i-n;
path[cnt][1] = e.to;
path[cnt][2] = e.flow;
++cnt;
}
}
}
printf("%d %d\n", flow, cnt);
for(int i=0; i<cnt; ++i) printf("%d %d %d\n", path[i][0], path[i][1], path[i][2]);
for(int i=0; i<MAXV; ++i) G[i].clear();
}
return 0;
}