流水线上有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;
}