poj 3436 网络流基础题

[题目链接](http://poj.org/problem?id=3436)
题意: 题意确实难读。
首先给出p,n 两个数 表示有p台机床来组装电脑,每台电脑有n个零件需要组装
接着p行,每行描述一台机床 共2*n+1个数字,
第一个数字表示每单位时间该机床能处理多少未完成品
接下来n个数字表示该机床能接受的未完成品类型 0表示该零件不能存在 1表示该零件必须存在 2表示该零件可存在
最后n个数字表示处理后 未完成品是什么样的。
问怎么样用这些机床构成生产线 使得单位产量最大
最后要你打印路径。

写的第一道不是那么裸的网络流题目,因为要打印路径 所以不能直接套模板。 
先按老套路,拆点建边。
建好图之后,跑一遍网络流。 
然后再遍历一遍原来的边,如果这条边有用的话,那他的流量肯定小于容量,把这些边全部找出来就行。
 

#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cstdio>
#define For(a,b,c) for(a=b;a<=c;a++)
#include<queue>
using namespace std;
int n,m;
int val[300];
const int inf = 0x3f3f3f3f;
const int MX=300 ;
const int MXE= 4 * MX * MX;
struct Edge {
        int u,v, w, nxt;
};
struct MaxFlow {
    Edge edge[MXE];
    int tot, num, s, t;
    int head[MX];
    void init() {
        memset(head, -1, sizeof(head));
        tot = 0;
    }
    void add(int u, int v, int w) {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].nxt = head[u];
        head[u] = tot++;
        edge[tot].u = v;
        edge[tot].v = u;
        edge[tot].w = 0;
        edge[tot].nxt = head[v];
        head[v] = tot++;
    }

    int  d[MX], vis[MX], gap[MX];
    void bfs() {
        memset(d, 0, sizeof(d));
        memset(gap, 0, sizeof(gap));
        memset(vis, 0, sizeof(vis));
        queue<int>q;
        q.push(t);
        vis[t] = 1;
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (int i = head[u]; ~i; i = edge[i].nxt) {
                int v = edge[i].v;
                if (!vis[v]) {
                    d[v] = d[u] + 1;
                    gap[d[v]]++;
                    q.push(v);
                    vis[v] = 1;
                }
            }
        }
    }

    int last[MX];
    int dfs(int u, int f) {
        if (u == t) return f;
        int sap = 0;
        for (int i = last[u]; ~i; i = edge[i].nxt) {
            int v = edge[i].v;
            if (edge[i].w > 0 && d[u] == d[v] + 1) {
                last[u] = i;
                int tmp = dfs(v, min(f - sap, edge[i].w));
                edge[i].w -= tmp;
                edge[i ^ 1].w += tmp;
                sap += tmp;
                if (sap == f) return sap;
            }
        }
        if (d[s] >= num) return sap;
        if (!(--gap[d[u]])) d[s] = num;
        ++gap[++d[u]];
        last[u] = head[u];
        return sap;
    }
    int solve(int st, int ed, int n) {
        int flow = 0;
        num = n;
        s = st;
        t = ed;
        bfs();
        memcpy(last, head, sizeof(head));
        while (d[s] < num) flow += dfs(s, inf);
        return flow;
    }
    void slove(vector<Edge> &V) {
        for(int i=0;i<tot;i+=2){
            if(edge[i].u>m) continue;
            if(edge[i].w<val[edge[i].u]){
                Edge cnt;
                int sum=val[edge[i].u]-edge[i].w;
                for(int j=head[edge[i].u+m];j!=-1;j=edge[j].nxt){
                    int v=edge[j].v;
                    if(v==2*m+1) continue;// 连向超级汇点的边要跳过
                    if(edge[j].w<20000) continue;// 反向边跳过
                    cnt.u=edge[i].u;
                    if(edge[j].w<inf){
                        cnt.v=edge[j].v;
                        cnt.w=inf-edge[j].w;
                        V.push_back(cnt);
                    }
                }
            }
        }
    }
} F;
int str[300][2][50];
bool check1(int a[],int len) {
    //for(int i=1; i<=len; i++)cout<<a[i]<<" ";
    //puts("");
    for(int i=1; i<=len; i++) {
        if(a[i]==1) return false;
    }
    return true;
}
bool check2(int a[],int len) {
    for(int i=1; i<=len; i++) {
        if(a[i]!=1) return false;
    }
    return true;
}
bool cmp(int a[],int b[],int len) {
    //for(int i=1; i<=len; i++)cout<<a[i]<<" ";
    //puts("");
    for(int i=1; i<=len; i++) {
        if(((a[i]==1 && b[i]==0)||(a[i]==0 && b[i]==1))) return false;
    }
    return true;
}
int main() {
    while(~scanf("%d %d",&n,&m)) {
        F.init();
        int cnt;
        for(int i=1; i<=m; i++) {
            scanf("%d",&val[i]);
            for(int j=1; j<=n; j++) {
                scanf("%d",&str[i][0][j]);
            }
            for(int j=1; j<=n; j++) {
                scanf("%d",&str[i][1][j]);
            }
        }
        // 建边
        for(int i=1; i<=m; i++) {
            if(check1(str[i][0],n)) {
                F.add(0,i,inf);
            }
            if(check2(str[i][1],n)) {
                F.add(i+m,2*m+1,inf);
            }
            F.add(i,i+m,val[i]);
            for(int j=1; j<=m; j++) {
                if(i==j) continue;
                if(cmp(str[i][1],str[j][0],n)) {
                    F.add(i+m,j,inf);
                }
            }
        }
        cout<<F.solve(0,2*m+1,2*m+2);
        vector<Edge> ans;
        F.slove(ans);
        cout<<" "<<ans.size()<<endl;
        for(int i=0;i<ans.size();i++){
            printf("%d %d %d\n",ans[i].u,ans[i].v,ans[i].w);
        }
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值