[BZOJ2055]80人环游世界 有上下界最小费用最大流
2055: 80人环游世界
Time Limit: 10 Sec Memory Limit: 64 MBDescription
想必大家都看过成龙大哥的《80天环游世界》,里面的紧张刺激的打斗场面一定给你留下了深刻的印象。现在就有这么
一个80人的团伙,也想来一次环游世界。
他们打算兵分多路,游遍每一个国家。
因为他们主要分布在东方,所以他们只朝西方进军。设从东方到西方的每一个国家的编号依次为1...N。假若第i个人的游历路线为P1、P2......Pk(0≤k≤N),则P1<P2<......<Pk。
众所周知,中国相当美丽,这样在环游世界时就有很多人经过中国。我们用一个正整数Vi来描述一个国家的吸引程度,Vi值越大表示该国家越有吸引力,同时也表示有且仅
有Vi个人会经过那一个国家。
为了节省时间,他们打算通过坐飞机来完成环游世界的任务。同时为了省钱,他们希望总的机票费最小。
明天就要出发了,可是有些人临阵脱逃,最终只剩下了M个人去环游世界。他们想知道最少的总费用,你能告诉他们吗?
Input
第一行两个正整数N,M。
第二行有N个不大于M正整数,分别表示V1,V2......VN。
接下来有N-1行。第i行有N-i个整数,该行的第j个数表示从第i个国家到第i+j个国家的机票费(如果该值等于-1则表示这两个国家间没有通航)。
Output
在第一行输出最少的总费用。
Sample Input
6 3
2 1 3 1 2 1
2 6 8 5 0
8 2 4 1
6 1 0
4 -1
4
2 1 3 1 2 1
2 6 8 5 0
8 2 4 1
6 1 0
4 -1
4
Sample Output
27
HINT
1<= N < =100 1<= M <= 79
题解:
做完上下界可行流和最大最小流还不算完,我们还可以搞上下界费用流。。。。。
我们考虑这道题的建模:
由于一共有m个人,所以我们额外建一个节点S‘,连一条S->S',上下界为[m,m],费用为0的弧,这样我们就限制了人数
对于每个国家"有且仅有"的限制,我们把国家拆点为入点i和出点i',对于国家i连一条i->i',上下界为[vi,vi],费用为0的弧,这样就可以限制通过这个国家的人数
当然,由于可以在任意一个地方开始旅行,所以我们还要对于每个国家i连一条S'->i,上下界为[0,inf],费用为0的弧
同理,由于可以在任意一个地方结束旅行,所以我们还要对于每个国家i连一条i'->T,上下界为[0,inf],费用为0的弧
而对于国家i,j间的机票钱,我们需要连一条i'->j,上下界为[0,inf],费用为val[i][j]的弧
在这样构图之后,我们考虑如何处理上下界:
依旧定义totflow数组表示某个点的入流量-出流量,那么我们给totflow[i]>0的点连i->tt的边,给totflow[i]<0的点连ss->i的边
然后我们考虑,最终的总费用应该是附加流的最小费用最大流+初始流的残量网络中每条边的剩余流量*边权
由于每条边不是费用为0,就是上下界残量(上界-下界)为0,所以残量网络带来的费用为0
所以我们只要计算附加流的最小费用最大流输出即可啦!
代码实现:
1 #include <cstdio> 2 #include <cstring> 3 using namespace std; 4 inline int min(int a,int b){return a<b?a:b;} 5 inline int max(int a,int b){return a>b?a:b;} 6 const int N=210,M=40010,inf=0x7fffffff; 7 struct edge{int zhong,next,val,flow;}s[M]; 8 int n,m,e=1,adj[N],totflow[N]; 9 int S,T,ss,tt,Station; 10 int hd,tl,q[M],ans,dis[N],pre[N]; 11 inline void add(int qi,int zhong,int flow,int val) 12 { 13 s[++e].zhong=zhong,s[e].next=adj[qi],adj[qi]=e, 14 s[e].flow=flow,s[e].val=val; 15 } 16 inline void Add(int a,int b,int c,int d) 17 {add(a,b,c,d),add(b,a,0,-d);} 18 bool vis[N]; 19 inline int Shoot() 20 { 21 int x=tt,f=inf; 22 while(x!=ss) 23 f=min(f,s[pre[x]].flow), 24 x=s[pre[x]^1].zhong; 25 x=tt; 26 while(x!=ss) 27 s[pre[x]].flow-=f,s[pre[x]^1].flow+=f, 28 x=s[pre[x]^1].zhong; 29 return f; 30 } 31 inline bool spfa() 32 { 33 memset(dis,0x7f,sizeof(dis)); 34 memset(vis,0,sizeof(vis)); 35 dis[ss]=0,vis[ss]=1,q[hd=tl=1]=ss; 36 register int i,j,x,u; 37 while(hd<=tl) 38 for(x=q[hd++],vis[x]=0,i=adj[x];i;i=s[i].next) 39 if(s[i].flow&&dis[(u=s[i].zhong)]>dis[x]+s[i].val) 40 { 41 pre[u]=i,dis[u]=dis[x]+s[i].val; 42 if(!vis[u])q[++tl]=u,vis[u]=1; 43 } 44 if(dis[tt]==dis[0])return 0; 45 ans+=dis[tt]*Shoot(); 46 return 1; 47 } 48 int main() 49 { 50 register int i,j,k,val,lim; 51 scanf("%d%d",&n,&m); 52 Station=2*n+1,S=Station+1,T=S+1,ss=T+1,tt=ss+1; 53 totflow[S]-=m,totflow[Station]+=m; 54 for(i=1;i<=n;++i) 55 { 56 scanf("%d",&lim); 57 totflow[i]-=lim,totflow[n+i]+=lim; 58 Add(Station,i,inf,0),Add(n+i,T,inf,0); 59 } 60 for(i=1;i<n;++i) 61 for(j=i+1;j<=n;++j) 62 { 63 scanf("%d",&val); 64 if(val!=-1)Add(i+n,j,inf,val); 65 } 66 for(i=1;i<=T;++i) 67 { 68 if(totflow[i]>0)Add(ss,i,totflow[i],0); 69 if(totflow[i]<0)Add(i,tt,-totflow[i],0); 70 } 71 Add(T,S,inf,0); 72 while(spfa()); 73 printf("%d\n",ans); 74 }
Progress is not created by contented people.