【有源汇点上下界最大流】[ZOJ3229]Shoot the Bullet

题目:
大意:有一个人,去给m个女孩儿拍照,第i个女孩至少拍Gi张,第k天最多拍Dk张,需要给Ck个女孩拍照,分别是Tk1, Tk2, …, TkCk,每个女孩至少Lki张,最多Rki张。

做法:就像无源汇点上下界最大流那样连边,最后从T到S连一条下届为0,上届为+∞的边即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 365
#define MAXM 1000
#define MAXC 100
#define INF 0x7fffffff
using namespace std;
int n,m,l[MAXC*MAXM+10],s,t,d[MAXN+MAXM+10],cnt,S,T,tot,dist[MAXN+MAXM+10],vd[MAXN+MAXM+10],num,flow;
struct node{
    int v,cap;
    node *next,*back;
}*adj[MAXN+MAXM+10],edge[(MAXC*MAXM+MAXN*2+MAXM*2)*2+10],*ecnt,*epos[MAXM*MAXC+10];
void addedge(int u,int v,int cap,int pos){
    node *p=++ecnt;
    p->v=v;
    p->cap=cap;
    epos[pos]=p;
    p->next=adj[u];
    adj[u]=p;
    p=p->back=++ecnt;
    p->back=ecnt-1;
    p->v=u;
    p->cap=0;
    p->next=adj[v];
    adj[v]=p;
}
void Read(int &x){
    char c;
    while(c=getchar(),c!=EOF)
        if(c>='0'&&c<='9'){
            x=c-'0';
            while(c=getchar(),c>='0'&&c<='9')
                x=x*10+c-'0';
            ungetc(c,stdin);
            return;
        }
    exit(0);
}
void read(){
    Read(n),Read(m);
    int i,c,v,cap,dd;
    s=0;
    t=n+m+1;
    for(i=1;i<=m;i++){
        Read(c);
        addedge(i,t,INF,0);
        d[t]+=c;
        d[i]-=c;
    }
    for(i=1;i<=n;i++){
        Read(c),Read(dd);
        addedge(s,i+m,dd,0);
        while(c--){
            Read(v),Read(l[++cnt]),Read(cap);
            d[i+m]-=l[cnt];
            d[++v]+=l[cnt];
            addedge(i+m,v,cap-l[cnt],cnt);
        }
    }
    S=t+1,T=S+1;
    for(i=0;i<=t;i++)
        if(d[i]>0)
            addedge(S,i,d[i],0),tot+=d[i];
        else if(d[i]<0)
            addedge(i,T,-d[i],0);
    addedge(t,s,INF,0);
}
int dfs(int u,int augu,const int S,const int T){
    if(u==T)
        return augu;
    int v,augv=0,mind=num-1,delta;
    for(node *p=adj[u];p;p=p->next){
        if(p->cap){
            v=p->v;
            if(dist[u]==dist[v]+1){
                delta=min(augu-augv,p->cap);
                delta=dfs(v,delta,S,T);
                p->cap-=delta;
                p->back->cap+=delta;
                augv+=delta;
                if(augv==augu||dist[S]>=num)
                    return augv;
            }
            mind=min(mind,dist[v]);
        }
    }
    if(!augv){
        if(!--vd[dist[u]])
            dist[S]=num;
        dist[u]=mind+1;
        vd[dist[u]]++;
    }
    return augv;
}
void sap(const int S,const int T){
    memset(dist,0,sizeof dist);
    memset(vd,0,sizeof vd);
    vd[0]=num;
    flow=0;
    while(dist[S]<num)
        flow+=dfs(S,INF,S,T);
}
void print(){
    printf("%d\n",flow);
    for(int i=1;i<=cnt;i++)
        printf("%d\n",epos[i]->back->cap+l[i]);
    puts("");
}
inline void init(){
    memset(adj,0,sizeof adj);
    memset(d,0,sizeof d);
    ecnt=edge;
    cnt=tot=0;
}
int main()
{
    while(1){
        init();
        read();
        num=T+1;
        sap(S,T);
        if(flow!=tot)
            puts("-1\n");
        else{
            adj[S]=adj[T]=0;
            flow=0;
            num=T+1;
            sap(s,t);
            print();
        }
    }
}

你可能感兴趣的:(C++,网络流)