网络流——最大流

poj 3436

题目大意:

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.csdn.net/big_heart_c

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值