标签: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 }
标签:nod 最小费用最大流 道路 cst oid std -- continue node
原文地址:https://www.cnblogs.com/pangbi/p/11823780.html