题目大意:
p个零件,N台机器,每台机器有其相对应的效率 Q 和经过这台机器时每个零件都有其对应的“输入说明”和“输出说明”,输入说明中 0 代表所加工的电脑进入这台机器时这个零件不能出现,1 代表必须出现,2 代表可有可无;输出说明中 0 代表所加工的电脑离开这台机器后这个零件不会出现,1 则代表会出现。
解题思路
1.以每台机器作为一个顶点,对每台机器进行拆点,同一台机器拆出来的两个点为互通的,且容量为该机器相对应的效率 Q,同时一个点代表“首”,记录输入说明,另一个点表示“尾”,记录输出说明。
2.每一“尾”点都遍历全部的”首”点,若其记录的说明与”首“点的说明相同,则进行连接,容量为无穷大。
3.添加超级源点 s,超级汇点 t 。遍历“首“点,将全为 0 或 2 的”首“点与 s 连接;遍历“尾“点,将全为 1 的”尾“点与 t 连接。
4.运用最大流算法,这里使用 Dinic 算法。
5.题目要求输出机器的连接状态,可以通过连接某两个机器之间的边是否有损失来判断某两个机器是否相连。
这里给出 Dinic 算法的模板
/*==================================================*\
| Dinic 最大流 O(V^2 * E)
| INIT: ne=2; head[] 置为0; addedge() 加入所有弧;
| CALL: flow(n, s, t);
\*==================================================*/
#define typec int // type of cost
const typec inf = 0x3f3f3f3f; // max of cost
struct edge {
int x, y, nxt;
typec c;
} bf[E];
int ne, head[N], cur[N], ps[N], dep[N];
void addedge(int x, int y, typec c) {
// add an arc(x -> y, c); vertex: 0 ~ n-1;
bf[ne].x = x;
bf[ne].y = y;
bf[ne].c = c;
bf[ne].nxt = head[x];
head[x] = ne++;
bf[ne].x = y;
bf[ne].y = x;
bf[ne].c = 0;
bf[ne].nxt = head[y];
head[y] = ne++;
}
typec flow(int n, int s, int t) {
typec tr, res = 0;
13
typef e[N];
int i, j, k, f, r, top;
while (1) {
memset(dep, -1, n * sizeof(int));
for (f = dep[ps[0] = s] = 0, r = 1; f != r; )
for (i = ps[f++], j = head[i]; j; j = bf[j].nxt) {
if (bf[j].c && -1 == dep[k = bf[j].y]) {
dep[k] = dep[i] + 1;
ps[r++] = k;
if (k == t) {
f = r;
break;
}
}
}
if (-1 == dep[t]) break;
memcpy(cur, head, n * sizeof(int));
for (i = s, top = 0; ; ) {
if (i == t) {
for (k = 0, tr = inf; k < top; ++k)
if (bf[ps[k]].c < tr)
tr = bf[ps[f = k]].c;
for (k = 0; k < top; ++k)
bf[ps[k]].c -= tr, bf[ps[k]^1].c += tr;
res += tr;
i = bf[ps[top = f]].x;
}
for (j=cur[i]; cur[i]; j = cur[i] = bf[cur[i]].nxt)
if (bf[j].c && dep[i]+1 == dep[bf[j].y]) break;
if (cur[i]) {
ps[top++] = cur[i];
i = bf[cur[i]].y;
} else {
if (0 == top) break;
dep[i] = -1;
i = bf[ps[--top]].x;
}
}
}
return res;
}
AC代码如下
//Memory: 288K Time: 0MS
#include<iostream>
#include<string.h>
#include<fstream>
using namespace std;
const int MAXN = 42*12;
//1 ≤ P ≤ 10, 1 ≤ N ≤ 50, 1 ≤ Qi ≤ 10000
#define typec int // type of cost
const typec inf = 10001;
int P,N;//part,machine
struct vertex {
int Q;//specifies performance
int S[11]; //input specification
} ver[105]; //机器
struct edge {
int x, y, nxt;
typec c;
} bf[(105*104)+1];
bool edge[107][107];//每条边的连接状态
int answer_num,E;//E表示边的条数
int ne, head[105], cur[105], ps[105], dep[105];
void addedge(int x, int y, typec c) {
// add an arc(x -> y, c); vertex: 0 ~ n-1;
E+=2;
bf[ne].x = x;
bf[ne].y = y;
bf[ne].c = c;
bf[ne].nxt = head[x];
head[x] = ne++;
bf[ne].x = y;
bf[ne].y = x;
bf[ne].c = 0;
bf[ne].nxt = head[y];
head[y] = ne++;
}
typec flow(int n, int s, int t) {
typec tr, res = 0;
int i, j, k, f, r, top;
while (1) {
memset(dep, -1, n * sizeof(int));
for (f = dep[ps[0] = s] = 0, r = 1; f != r; )
for (i = ps[f++], j = head[i]; j; j = bf[j].nxt) {
if (bf[j].c && -1 == dep[k = bf[j].y]) {
dep[k] = dep[i] + 1;
ps[r++] = k;
if (k == t) {
f = r;
break;
}
}
}
if (-1 == dep[t]) break;
memcpy(cur, head, n * sizeof(int));
for (i = s, top = 0; ; ) {
if (i == t) {
for (k = 0, tr = inf; k < top; ++k)
if (bf[ps[k]].c < tr)
tr = bf[ps[f = k]].c;
for (k = 0; k < top; ++k)
bf[ps[k]].c -= tr, bf[ps[k]^1].c += tr;
res += tr;
i = bf[ps[top = f]].x;
}
for (j=cur[i]; cur[i]; j = cur[i] = bf[cur[i]].nxt)
if (bf[j].c && dep[i]+1 == dep[bf[j].y]) break;
if (cur[i]) {
ps[top++] = cur[i];
i = bf[cur[i]].y;
} else {
if (0 == top) break;
dep[i] = -1;
i = bf[ps[--top]].x;
}
}
}
return res;
}
void connect() {
for(int i =0 ; i<N; i++) { //尾->首
for(int j = 0; j<N; j++) {
if(i != j) {//不能首尾相连
bool isgoon = true;
for(int k =0 ; k<P; k++) {
if(ver[j*2].S[k] == 2)
continue;
if(ver[i*2 +1].S[k] != ver[j*2].S[k]) {
isgoon = false;
break;
}
}
if(isgoon) {
addedge(i*2 +1,j*2,inf);//相等则连边
edge[i*2 +1][j*2] = 1;
}
}
}
}
for(int i =0 ; i<N; i++) { //添加超级源点,汇点
bool head_all_is_one = true,tail_all_is_one = true;
for(int j = 0; j<P; j++) {
if(!(ver[i*2].S[j] == 2 || ver[i*2].S[j] == 0 ))
head_all_is_one = false;
if(ver[i*2+1].S[j] != 1)
tail_all_is_one = false;
}
if(head_all_is_one) {
addedge(2*N,i*2,inf);//第 2*N 个点为超级源点
edge[2*N][i*2] = 1;
}
if(tail_all_is_one) {
addedge(i*2+1,2*N+1,inf);//第 2*N+1 个点为超级汇点
edge[i*2+1][2*N+1] = 1;
}
}
}
int main() {
//input
while(cin>>P>>N) {
//init
ne = 2;
E = 0;
memset(head,0,sizeof(head));
memset(edge,0,sizeof(edge));
answer_num = 0;
for(int i=0; i<N; i++) {
cin>>ver[2*i].Q;
ver[2*i + 1].Q = ver[2*i].Q;
for(int j = 0; j<P; j++) {
int temp;
cin>>ver[2*i].S[j];
}
for(int k = 0; k<P; k++) {
cin>>ver[2*i+1].S[k]; //存储output
}
}
//拆点
for(int i =0 ; i<N; i++) {
addedge(2*i,2*i +1,ver[2*i].Q);
addedge(2*i+1,2*i,ver[2*i].Q);
edge[2*i][2*i +1] = 1;
edge[2*i+1][2*i] = 1;
}
connect();
cout<<flow(2*N+2,2*N,2*N+1)<<" ";
for(int i = 0; i<E; i++) {
if(bf[i].x == 2*N || bf[i].y == 2*N +1 || (bf[i].x/2) == (bf[i].y/2)) {
continue;
}
if(bf[i].c != inf && edge[bf[i].x][bf[i].y])
answer_num++;
}
cout<<answer_num<<endl;
for(int i = 0; i<E; i++) {
if(bf[i].x == 2*N || bf[i].y == 2*N +1 || (bf[i].x/2) == (bf[i].y/2)) {
continue;
}
if(bf[i].c != inf && edge[bf[i].x][bf[i].y])
cout<<bf[i].x/2+1<<" "<<bf[i].y/2+1<<" "<<inf - bf[i].c<<endl;
}
}
}
算法还能进行优化。
如有错误,还望指出!
转载请注明出处:http://blog.youkuaiyun.com/big_heart_c