zoj 3229 上下限网络流

上下限网络流
做法:假设有边x-y(a,b),建立临时节点ss,tt,连接x-y(0,b-a),x-ss(0,a),tt-y(0,a);
最后连接t-s(0,inf);
先对tt-ss跑最大流,如果tt的每一条边都是满流,那么就存在解,否则无解,
如果想求最大流,只需要在残余图上跑s-t的最大流,因为ss点没有出边,并且任意点到ss的流量为0,所以可以保证在残余图上跑最大流不会影响到tt-ss的流。所以可以得出答案,注意:如果用s点的出边的反向边求最大流,要注意要减去一个inf,因为连接了一条t-s(0,inf)的边。
也可以直接跑最大流、

 #include<bits/stdc++.h>
using namespace std;

template<int N,typename T>
struct MaxFlow {
    int s,t,head[N],etot,que[N],qf,qe,dis[N],cur[N];
    struct Edge {int v,next; T cap;}g[501000];
    void init() {
        memset(head,-1,sizeof(head)); etot = 0;
    }
    void add_edge(int u,int v,T cap) {
        //cout << "!!!" <<u <<' '<< v << ' '<< cap << endl;
        g[etot].v = v; g[etot].next = head[u]; g[etot].cap = cap; head[u] = etot ++;
        g[etot].v = u; g[etot].next = head[v]; g[etot].cap = 0; head[v] = etot ++;
    }
    bool bfs() {
        memset(dis,-1,sizeof(dis));
        memcpy(cur,head,sizeof(cur));
        dis[t] = N;
        qf = qe = 0;
        que[qe++] = t;
        while (qf!=qe) {
            int u = que[qf++];
            for (int i = head[u]; i != -1; i = g[i].next) {
                Edge &e = g[i];
                if (g[i^1].cap && dis[e.v] == -1) {
                    dis[e.v] = dis[u] - 1;
                    que[qe++] = e.v;
                }
            }
        }
        return dis[s] != -1;
    }
    T dfs(int u,T a) {
        if (u==t) return a;
        T flow = 0,f;
        for (int &i = cur[u]; i != -1; i = g[i].next) {
            Edge &e = g[i];
            if (e.cap && dis[e.v] > dis[u]) {
                f = dfs(e.v,std::min(a,e.cap));
                flow += f;
                e.cap -= f;
                g[i^1].cap += f;
                a -= f;
                if (a==0) break;
            }
        }
        if (flow==0) dis[u] = -1;
        return flow;
    }
    T dinic(int _s,int _t) {
        s = _s; t = _t;
        T flow = 0;
        while (bfs()) flow += dfs(s,(T)1e30);
        return flow;
    }
};

MaxFlow<2000+7,int> mf;
int in[2000+7];//统计每个点到ss或者到tt的流量,这里把多条边合并
int su[100000];//每个点的最小流量,最后要加上
int day[500];
int main(){
    int n,m;
    while(scanf("%d %d",&n,&m) == 2){
        memset(in,0,sizeof(in));
        int s = 0,t = n+m+1,ss = n+m+2,tt = n+m+3;
        mf.init();
        int tot = 0;
        int inf = 1e9;
        int ret = 0;
        for(int i = 1;i <= m;i ++){
            int now;
            scanf("%d",&now);
            in[n+i] -= now;
            in[t] += now;
        }
        for(int i = 1;i <= n;i ++){
            int c,d;
            scanf("%d %d",&c,&d);
            day[i] = d;
            for(int j = 1;j <= c;j ++){
                int x,l,r;
                scanf("%d %d %d",&x,&l,&r);
                su[tot++] = l;
                mf.add_edge(i,n+x+1,r-l);//连接残余边
                in[i] -= l;
                in[n+x+1] += l;
            }
        }
        for(int i = 1;i <= n;i ++) mf.add_edge(s,i,day[i]);
        for(int i = 1;i <= m;i ++) mf.add_edge(n+i,t,inf);
        mf.add_edge(t,s,inf);
        for(int i = 0;i <= n+m+1;i ++){//处理连接ss和tt的边
            if(in[i] > 0) mf.add_edge(tt,i,in[i]),ret += in[i];
            if(in[i] < 0) mf.add_edge(i,ss,-in[i]);
        }
        int mxf = mf.dinic(tt,ss);
        if(mxf == ret){
            printf("%d\n",mf.dinic(s,t));
            for(int i = 0;i < tot;i ++){
                printf("%d\n",mf.g[i*2+1].cap+su[i]);
            }
        }
        else puts("-1");
        puts("");
    }
	return 0;
}



猜你喜欢

转载自blog.csdn.net/zstu_zy/article/details/82859040
ZOJ