网络流24题之太空飞行计划

建模方式:

1 :构造一个图 N ,顶点有 Ii(1<=i<=n) , Ej(1<=j<=m) 以及一个源 S 和汇 T
2 :从源点出发,向每个实验 Ei 引出一条容量为 Pi 的有向边
3 :从每个仪器 Ij 出发,向汇点引出一条容量为 costi 的有向边
4 :每个实验分别向所需的仪器引出一条容量为 + 的有向边

这样用总收入减去最大流即为答案,统计方式可以采用删去一边然后暴力跑网络流判断。

By:大奕哥

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int N=1005,inf=1e9;
  4 int head[N],cnt=-1,p[N],cost[N],v[N],m,n,ulen,s,t;
  5 char c[N];
  6 vector<int>ex[N];
  7 queue<int>q;
  8 struct node{
  9     int to,nex,w;
 10 }e[N<<1],a[N<<1];
 11 void add(int x,int y,int w)
 12 {
 13     e[++cnt].to=y;e[cnt].nex=head[x];head[x]=cnt;e[cnt].w=w;
 14     e[++cnt].to=x;e[cnt].nex=head[y];head[y]=cnt;e[cnt].w=0;
 15 }
 16 bool bfs(int x,int y)
 17 {
 18     memset(v,-1,sizeof(v));
 19     v[x]=0;q.push(x);
 20     while(!q.empty())
 21     {
 22         int x=q.front();q.pop();
 23         for(int i=head[x];i!=-1;i=e[i].nex)
 24         {
 25             int y=e[i].to;
 26             if(!e[i].w||v[y]!=-1)continue;
 27             v[y]=v[x]+1;
 28             q.push(y);
 29         }
 30     }
 31     return v[y]!=-1;
 32 }
 33 int dfs(int x,int w,int yy)
 34 {
 35     if(!w||x==yy)return w;
 36     int s=0;
 37     for(int i=head[x];i!=-1;i=e[i].nex)
 38     {
 39         int y=e[i].to;
 40         if(v[y]!=v[x]+1||!e[i].w)continue;
 41         int flow=dfs(y,min(w-s,e[i].w),yy);
 42         s+=flow;e[i].w-=flow;e[i^1].w+=flow;
 43         if(!flow)v[y]=-1;
 44         if(s==w)return s;
 45     }
 46     return s;
 47 }
 48 int dinic(int x,int y)
 49 {
 50     int ans=0;
 51     while(bfs(x,y)){
 52         ans+=dfs(x,inf,y);    
 53     }
 54     return ans;
 55 }
 56 void copy()
 57 {
 58     for(int i=0;i<=cnt;++i)a[i].w=e[i].w;
 59 }
 60 void copy2()
 61 {
 62     for(int i=0;i<=cnt;++i)e[i].w=a[i].w;
 63 }
 64 bool use1[N],use2[N];
 65 int main()
 66 {
 67     scanf("%d%d",&m,&n);
 68     int sum=0,ans,num;
 69     memset(head,-1,sizeof(head));
 70     for(int i=1;i<=m;++i)
 71     {
 72         scanf("%d",&p[i]);
 73         sum+=p[i];
 74         memset(c,0,sizeof(c));
 75         cin.getline(c,10000);
 76         ulen=0;
 77         while(sscanf(c+ulen,"%d",&num)==1)
 78         {
 79             ex[i].push_back(num);
 80             if(!num)ulen++;
 81             else while(num)
 82             {
 83                 num/=10;
 84                 ulen++;
 85             }
 86             ulen++;
 87         }
 88     }
 89     for(int i=1;i<=n;++i)scanf("%d",&cost[i]);
 90     s=0,t=1000;
 91     for(int i=1;i<=m;++i)
 92     add(s,i,p[i]);
 93     for(int i=1;i<=n;++i)
 94     add(i+m,t,cost[i]);
 95     for(int i=1;i<=m;++i)
 96     {
 97         for(int j=0;j<ex[i].size();++j)
 98         add(i,ex[i][j]+m,inf);
 99     }
100     copy();
101     ans=dinic(s,t);
102     for(int i=head[t];i!=-1;i=e[i].nex)
103     {
104         copy2();
105         int tmp=e[i^1].w;
106         e[i^1].w=0;
107         int pre=dinic(s,t);
108         if(ans-pre==tmp)use1[e[i].to-m]=1;
109         e[i^1].w=tmp;
110     }
111     for(int i=1;i<=m;++i)
112     {
113         use2[i]=1;
114         for(int j=0;j<ex[i].size();++j)
115         if(!use1[ex[i][j]])
116         {
117             use2[i]=0;break;
118         }
119     }
120     for(int i=1;i<=m;++i)
121     if(use2[i])printf("%d ",i);
122     puts("");
123     for(int i=1;i<=n;++i)
124     if(use1[i])printf("%d ",i);
125     puts("");
126     printf("%d\n",sum-ans);
127     return 0;
128 }

 

posted @ 2018-01-26 17:02  大奕哥&VANE  阅读(159)  评论(0编辑  收藏  举报