最大流——Luogu2762 [网络流24题]太空飞行计划问题

来源:互联网 发布:ipad程序员必备app 编辑:程序博客网 时间:2024/06/05 19:43

题面:Luogu2762
网络流24题之二
最大权闭合子图 ,首先建图
我们先从源点向每个实验连上权值为实验收益的边,再从每个器材向汇点权值为配置费用的边
然后每对配对方案连一条权值为INF的边
跑最小割即可,答案就是实验收益总和-最大流
具体证明不证了
两个比较容易炸的地方:

  • 读入:挺恶心的因为并没有告诉你到底配对的方案数有多少,请不要使用类似读入优化的读入方式(我试过好像这对于换行符不敏感。。。),推荐字符串getline读入后处理
  • 输出方案:首先找器材,我们可以试着把器材到汇点的边删去再跑最小割(放心,这题n<=50 m<=50 是T不掉的)然后对比答案如果后者答案少的就是权值那么说明这条边满流,器材可用,继而实验也可以推出来了
#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<iostream>#include<cstdlib>#include<string>#include<ctime>#include<queue>#include<climits>using namespace std;string ctrmmp;//请忽视这个变量名……读入专用bool an[10001];int dist[10001],cur[10001],n,m,s,t,sum=0,v[100001];int nedge=-1,p[100001],c[100001],C[100001],nex[100001],head[100001];inline void addedge(int x,int y,int z){    p[++nedge]=y;C[nedge]=c[nedge]=z;    nex[nedge]=head[x];head[x]=nedge;}inline bool bfs(int s,int t){    queue<int>q;q.push(s);    memset(dist,-1,sizeof dist);dist[s]=1;    while(!q.empty()){        int now=q.front();q.pop();        for(int k=head[now];k>-1;k=nex[k])if(c[k]&&dist[p[k]]==-1){            dist[p[k]]=dist[now]+1;q.push(p[k]);        }    }    return dist[t]>-1?1:0;}inline int dfs(int x,int low){    if(x==t)return low;    int a,used=0;    for(int k=cur[x];k>-1;k=nex[k])if(c[k]&&dist[p[k]]==dist[x]+1){        a=dfs(p[k],min(c[k],low-used));        if(a)c[k]-=a,c[k^1]+=a,used+=a;        if(c[k])cur[x]=k;        if(used==low)break;    }    if(!used)dist[x]=-1;    return used;}inline int dinic(){    int flow=0;    while(bfs(s,t)){        for(int i=s;i<=t;i++)cur[i]=head[i];        flow+=dfs(s,1e9);    }    return flow;}int main(){    memset(p,-1,sizeof p);memset(nex,-1,sizeof nex);    memset(c,-1,sizeof c);memset(head,-1,sizeof head);    scanf("%d%d",&n,&m);    s=0;t=n+m+1;    for(int i=1;i<=n;i++){        int v;scanf("%d",&v);addedge(s,i,v);addedge(i,s,0);sum+=v;        getline(cin,ctrmmp);ctrmmp+=' ';int l=ctrmmp.size();        int k=0;        for(int j=0;j<l;j++){            if(ctrmmp[j]>='0'&&ctrmmp[j]<='9')k=k*10+ctrmmp[j]-'0';            else if(k)addedge(i,n+k,1e9),addedge(n+k,i,0),k=0;        }//读入    }    for(int i=1;i<=m;i++){        int x;scanf("%d",&x);        addedge(n+i,t,x);addedge(t,n+i,0);    }    int ans=dinic();    for(int k=head[t];k>-1;k=nex[k]){        memcpy(c,C,sizeof(C));        int rp=c[k^1];c[k^1]=0;        if(ans-dinic()==rp)an[p[k]-n]=1;    }//记录器材是否可行    for(int i=1;i<=n;i++){        bool flag=1;        for(int k=head[i];k>-1;k=nex[k])if(p[k]&&!an[p[k]-n]){flag=0;break;}        if(flag)printf("%d ",i);    }//记录实验是否可行    puts("");for(int i=1;i<=m;i++)if(an[i])printf("%d ",i);    printf("\n%d",sum-ans);    return 0;}
阅读全文
1 0
原创粉丝点击