导航

Codeforces 730I [费用流]

Posted on 2016-10-26 22:07  tun~  阅读(370)  评论(0编辑  收藏  举报
/*
不要低头,不要放弃,不要气馁,不要慌张
题意:
给两行n个数,要求从第一行选取a个数,第二行选取b个数使得这些数加起来和最大。
限制条件是第一行选取了某个数的条件下,第二行不能选取对应位置的数。

思路:
比赛的时候一直在想如何dp。没有往网络流的方向多想想。赛后看到tag想了想,咦,费用流可做。
所以思路是最小费用最大流,dp如今都不知如何做。
将一个位置拆分成3个点,从超级源点分别到1号点连容量为a,价值为0 的边,往2号点连容量为b,价值为0的边。
对于每个位置,从1号点和2号点分别向每个位置拆分出的第一个点连一条容量为1,价值为0的边。然后从该点分别向其它两个点连容量为1,价值为
给定的点,然后这两个点均向超级汇点连接一条容量为1价值为0的边。
跑一下最小费用最大流。





*/
#include<stdio.h>
#include<queue>
#define MAXN 55000
#define MAXM 20002*5
#define INF  0x3f3f3f3f
using namespace std;
int a[MAXN],b[MAXN];
int n;
//起点编号必须最小,终点编号必须最大
bool vis[MAXN];                    //spfa中记录是否在队列里边
struct edge{
    edge *next,*op;                //op是指向反向边
    int t,c,v;                     //t下一个点编号,c容量,v权值
}ES[MAXM],*V[MAXN];                //ES边静态邻接表,V点的编号
int N,M,S,T,EC=-1;                 //S源点最小,T汇点最大,EC当前边数
int demond[MAXN],sp[MAXN],prev[MAXN]; //spSPFA中记录距离,prev记录上一个点路径
edge *path[MAXN];                  //与prev同步记录,记录到上一条边
void addedge(int a,int b,int v,int c=INF){
    edge e1={V[a],0,b,c,v},e2={V[b],0,a,0,-v};
    ES[++EC]=e1;V[a]=&ES[EC];
    ES[++EC]=e2;V[b]=&ES[EC];
    V[a]->op=V[b];V[b]->op=V[a];
}
void init(){
    int num1,num2;
    scanf("%d%d%d",&n,&num1,&num2);
    for(int i=1;i<=n;i++)scanf("%d",a+i);
    for(int i=1;i<=n;i++)scanf("%d",b+i);
    S=0;T=3*n+3;
    EC=-1;
    for(int i=1;i<=n;i++){
        addedge(S,i,0,1);
        addedge(i,n+i,-a[i],1);
        addedge(i,n*2+i,-b[i],1);
        addedge(n+i,T-2,0,1);
        addedge(n*2+i,T-1,0,1);
    }
    addedge(T-2,T,0,num1);
    addedge(T-1,T,0,num2);
}
bool SPFA(){
    int u,v;
    for(u=S;u<=T;u++){
        sp[u]=INF;
    }
    queue<int>q;
    prev[S]=-1;
    q.push(S);
    sp[S]=0;
    vis[S]=1;
    while(!q.empty()){
        u=q.front();
        vis[u]=0;
        q.pop();
        for(edge *k=V[u];k;k=k->next){
            v=k->t;
            if(k->c>0&&sp[u]+k->v<sp[v]){
                sp[v]=sp[u]+k->v;
                prev[v]=u;
                path[v]=k;
                if(vis[v]==0){
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    return sp[T]!=INF;
}
int argument(){
    int i,cost=INF,flow=0;
    edge *e;
    for(i=T;prev[i]!=-1;i=prev[i]){
        e=path[i];
        if(e->c<cost)cost=e->c;
    }
    for(int i=T;prev[i]!=-1;i=prev[i]){
        e=path[i];
        e->c-=cost;e->op->c+=cost;
        flow+=e->v*cost;
    }
    return flow;
}
int maxcostflow(){
    int Flow=0;
    while(SPFA()){
        Flow+=argument();
    }
    return Flow;
}
int main(){
    init();
    printf("%d\n",-maxcostflow());
    for(int i=1;i<=n;i++){
        for(edge *it=V[i+n];it;it=it->next){
            if(it->t<=n&&it->c>0)printf("%d ",i);
        }
    }
    puts("");
    for(int i=1;i<=n;i++){
        for(edge *it=V[i+2*n];it;it=it->next){
            if(it->t<=n&&it->c)printf("%d ",i);
        }
    }
    return 0;
}