LA 3487Duopoly(图论--网络流最小割 经典题)

Posted konjac蒟蒻

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LA 3487Duopoly(图论--网络流最小割 经典题)相关的知识,希望对你有一定的参考价值。

题意:一个公司有一些资源,每种只有1割,有A、B两个公司分别对其中一些资源进行分组竞标。问卖资源的公司的最大收益。

解法:最小割。将A公司的竞标与源点相连,B公司的与汇点相连,边容量为竞标价。而A、B公司的竞标中有资源冲突的竞标之间连一条边,容量为INF。这样的最大收益就是 总竞标出价-割去竞标的边的价格的最小值。

问题!!dinic函数那里,我竟然2种打法相差了近乎3秒,也就是dfs函数流了很多次。。。(?Д?≡?Д?)

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<queue>
  6 using namespace std;
  7 
  8 const int M=6100,N=300010,P=35,NN=6100,MM=240000,INF=1010;
  9 int m,mm,len;
 10 int id[N],last[NN],d[NN];
 11 struct edge{int y,fl,next;}a[MM];
 12 queue<int> q;
 13 
 14 int mmin(int x,int y) {return x<y?x:y;}
 15 void ins(int x,int y,int fl)
 16 {
 17     a[++len].y=y,a[len].fl=fl;
 18     a[len].next=last[x],last[x]=len;
 19     a[++len].y=x,a[len].fl=0;
 20     a[len].next=last[y],last[y]=len;
 21 }
 22 bool bfs(int st,int ed)
 23 {
 24     while (!q.empty()) q.pop();
 25     memset(d,0,sizeof(d));
 26     q.push(st), d[st]=1;
 27     while (!q.empty())
 28     {
 29       int x=q.front(); q.pop();
 30       for (int i=last[x];i;i=a[i].next)
 31       {
 32         int y=a[i].y;
 33         if (!a[i].fl||d[y]) continue;
 34         d[y]=d[x]+1, q.push(y);
 35       }
 36     }
 37     return d[ed];
 38 }
 39 int dfs(int x,int flow,int ed)
 40 {
 41     if (x==ed) return flow;
 42     int h=0;
 43     for (int i=last[x];i;i=a[i].next)
 44     {
 45       int y=a[i].y;
 46       if (!a[i].fl||d[y]!=d[x]+1) continue;
 47       int t=dfs(y,mmin(flow-h,a[i].fl),ed);
 48       h+=t;
 49       a[i].fl-=t,a[i^1].fl+=t;
 50       if (h==flow) break;
 51     }
 52     if (!h) d[x]=0;
 53     return h;
 54 }
 55 int Max_flow(int st,int ed)
 56 {
 57     int h=0,p;
 58     while(bfs(st,ed)) //h+=dfs(st,INF,ed);//slower a lot,very strange......
 59       while(p=dfs(st,INF,ed)) h+=p;
 60     return h;
 61 }
 62 int main()
 63 {
 64     int T;
 65     scanf("%d",&T);
 66     for (int kase=1;kase<=T;kase++)
 67     {
 68       int d,x; char c;
 69       int st=1,ed=2,sum=0;
 70       len=1;
 71       memset(last,0,sizeof(last));
 72       memset(id,0,sizeof(id));
 73       scanf("%d",&m);
 74       for (int i=1;i<=m;i++)
 75       {
 76         scanf("%d",&d); c=getchar();
 77         sum+=d, ins(st,i+2,d);
 78         while (c!=\n)
 79         {
 80           scanf("%d",&x);
 81           id[x]=i+2, c=getchar();
 82         }
 83       }
 84       scanf("%d",&mm);
 85       for (int i=1;i<=mm;i++)
 86       {
 87         scanf("%d",&d); c=getchar();
 88         sum+=d, ins(i+m+2,ed,d);
 89         while (c!=\n)
 90         {
 91           scanf("%d",&x);
 92           if (id[x]) ins(id[x],i+m+2,INF);
 93           c=getchar();
 94         }
 95       }
 96       int ans=Max_flow(st,ed);
 97       printf("Case %d:\n%d\n",kase,sum-ans);
 98       if (kase<T) printf("\n");
 99     }
100     return 0;
101 }

 

以上是关于LA 3487Duopoly(图论--网络流最小割 经典题)的主要内容,如果未能解决你的问题,请参考以下文章

LA3487最小割-经典模型 两种方法

图论之最大流问题(三)

图论算法的数学模型

网络流基础-最大流最小割定理

网络流问题

运筹学-图论实例