码迷,mamicode.com
首页 > 其他好文 > 详细

sap模板

时间:2019-11-09 00:48:44      阅读:96      评论:0      收藏:0      [点我收藏+]

标签:nod   最小费用最大流   道路   cst   oid   std   --   continue   node   

给出一张N(N<=100)个点,M(M<=1000条)边的有向图。每个点上都有一些人。每条边有4个属性(u,v,w,p)。这些边分为三种:(1)p<0时,表示这条边是隧道,这条隧道从u连向v,虽然如果想通过这条隧道的话没有流量限制,但可以最多只容纳w人;(2)p=0时,这条边是道路,由u连向v,通过没有流量限制;(3)p>0时,表示这条边是古老的桥,u连向v,如果不修这座桥,则只能通过1人,但是如果花费w的费用修桥的话,则通过这座桥的流量便没有限制。桥的总数<12。求使得最多的人能够躲到隧道里时候的人数和在该情况下的最小费用。

感觉不管是用费用流还是用最大流都要枚举每条桥是否会去修。很难将一座桥无论是修还是不修的两种方案同时表示在一张图里面。比方说,要用费用流来做,你要去修的话,首先对应一条cap=1,cost=w的边,你修完了之后,你不知道将来会流多少流量,所以还会对应一条cap=inf,cost=0的边,这样子如果用最小费用最大流来跑的话,无法保证先去走那条必须先走的cap=1,cost=w的边。

又由于桥的总数不是太多,所以考虑枚举。首先,从源点S向各个点i连一条边,cap=这个点原来有的人数(S,i,num);接下来,对于每条普通的道路,有边(u,v,inf);然后,如果我们决定去修一座桥i,有边(u,v,inf),同时记录花费w,如果不去修这座桥,有边(u,v,1);最后,对于每个隧道i,我们需要另外设置一个点xi来表示这个隧道的容量w,因此这里有三条边(u,xi,inf),(xi,v,inf),(xi,T,w)。然后跑最大流记录下最小费用。

(摘自别人博客)

这里贴这个代码纯粹是为了记一个sap的模板

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<queue>
  4 #include<math.h>
  5 #include<string.h>
  6 using namespace std;
  7 const int inf=0x3f3f3f3f;
  8 const int maxn=1e4;
  9 int nodesum=0;   //sap必备,图中点的个数,包括汇点源点。
 10 int a[110];
 11 struct Node
 12 {
 13     int u,v,w;
 14 };
 15 Node sto1[maxn],sto2[maxn],sto3[maxn];  //这是这道题才需要的数据
 16 struct node
 17 {
 18     int u,v,w,next;
 19 }G[maxn]; int head[maxn]; int num=-1;
 20 int dep[maxn]; int gap[maxn];//gap[x]=y :说明残留网络中dep[i]==x的个数为y
 21 //dep gap都是sap的参数
 22 void init()
 23 {
 24     num=-1;
 25     memset(head,-1,sizeof(head));
 26 }
 27 void add(int u,int v,int w)
 28 {
 29     G[++num].u=u;G[num].v=v;G[num].w=w;G[num].next=head[u];head[u]=num;
 30     G[++num].u=v;G[num].v=u;G[num].w=0;G[num].next=head[v];head[v]=num;
 31 }
 32 void BFS(int st,int ed)
 33 {
 34     memset(dep,-1,sizeof(dep));
 35     memset(gap,0,sizeof(gap));
 36     gap[0]=1;
 37     int que[maxn];
 38     int left,right;
 39     left=right=0;
 40     dep[ed]=0;
 41     que[right++]=ed;
 42     while(left!=right){
 43         int u=que[left++];
 44         if(left==maxn)left=0;
 45         for(int i=head[u];i!=-1;i=G[i].next){
 46             int v=G[i].v;
 47             if(dep[v]!=-1)continue;
 48             que[right++]=v;
 49             if(right==maxn)right=0;
 50             dep[v]=dep[u]+1;
 51             ++gap[dep[v]];
 52         }
 53     }
 54 }
 55 int sap(int st,int ed)
 56 {
 57     int res=0;
 58     BFS(st,ed);
 59     int cur[maxn];
 60     int S[maxn];
 61     int top=0;
 62     memcpy(cur,head,sizeof(head));
 63     int u=st;
 64     int i;
 65     while(dep[st]<nodesum){
 66         if(u==ed){
 67             int temp=inf;
 68             int inser;
 69             for(i=0;i<top;i++)
 70                if(temp>G[S[i]].w){
 71                    temp=G[S[i]].w;
 72                    inser=i;
 73                }
 74             for(i=0;i<top;i++){
 75                 G[S[i]].w-=temp;
 76                 G[S[i]^1].w+=temp;
 77             }
 78             res+=temp;
 79             top=inser;
 80             u=G[S[top]].u;
 81         }
 82         if(u!=ed&&gap[dep[u]-1]==0)//出现断层,无增广路
 83           break;
 84         for(i=cur[u];i!=-1;i=G[i].next)
 85             if(G[i].w!=0&&dep[u]==dep[G[i].v]+1) break;
 86         if(i!=-1){
 87             cur[u]=i;
 88             S[top++]=i;
 89             u=G[i].v;
 90         }
 91         else{
 92             int min=nodesum;
 93             for(i=head[u];i!=-1;i=G[i].next){
 94                 if(!G[i].w)continue;
 95                 if(min>dep[G[i].v]){
 96                     min=dep[G[i].v];
 97                     cur[u]=i;
 98                 }
 99             }
100             --gap[dep[u]];
101             dep[u]=min+1;
102             ++gap[dep[u]];
103             if(u!=st)u=G[S[--top]].u;
104         }
105     }
106     return res;
107 }
108 int main()
109 {
110     int n,m;
111     while(scanf("%d%d",&n,&m)!=EOF){
112         int s=0,t=n+2*m+1;
113         int len1=0;int len2=0;int len3=0;
114         for(int i=1;i<=n;i++) scanf("%d",&a[i]);
115         for(int i=1;i<=m;i++){
116             int u,v,w,flag;
117             scanf("%d%d%d%d",&u,&v,&w,&flag);
118             if(flag<0){
119                 //隧道;
120                 len2++;
121                 sto2[len2].u=u;
122                 sto2[len2].v=v;
123                 sto2[len2].w=w;
124             }
125             else if(!flag){
126                 //道路最为普通,貌似这样建就好了;
127                 //没隧道,不用接到汇点;
128                 len3++;
129                 sto3[len3].u=u;
130                 sto3[len3].v=v;
131                 sto3[len3].w=w;
132             }
133             else{
134                 sto1[len1].u=u;
135                 sto1[len1].v=v;
136                 sto1[len1].w=w;
137                 len1++;
138             }
139         }
140         nodesum=1+n+1+len2;
141         int mxpeople=0,mncost=inf;
142         for(int i=0;i<(1<<len1);i++){
143             init();
144             for(int j=1;j<=n;j++) add(s,j,a[j]);  //原点接城市点
145 
146             int cost=0;  //
147             for(int j=0;j<len1;j++){
148                 if(i&(1<<j)){
149                     add(sto1[j].u,sto1[j].v,inf);
150                     cost+=sto1[j].w;
151                 }
152                 else add(sto1[j].u,sto1[j].v,1);
153             }
154 
155             int node1=n; //隧道
156             for(int j=1;j<=len2;j++){
157                 node1++;
158                 add(sto2[j].u,node1,inf);
159                 add(node1,sto2[j].v,inf);
160                 add(node1,t,sto2[j].w);
161             }
162             for(int j=1;j<=len3;j++) add(sto3[j].u,sto3[j].v,inf); //
163             int people=sap(s,t);
164             if(people>mxpeople){
165                 mxpeople=people;
166                 mncost=cost;
167             }
168             else if(people==mxpeople){
169                 mncost=min(mncost,cost);
170             }
171         }
172         if(!mxpeople) printf("Poor Heaven Empire\n");
173         else printf("%d %d\n",mxpeople,mncost);
174     }
175     return 0;
176 }

 

sap模板

标签:nod   最小费用最大流   道路   cst   oid   std   --   continue   node   

原文地址:https://www.cnblogs.com/pangbi/p/11823780.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!