bzoj 2055 80人环游世界

有源汇上下界最小费用可行流。

将每个国家拆点。

源点向一个新建节点连一条上界为总人数下界为0费用为0的边。

新建节点向每个国家的入点连一条上界为正无穷下界为0费用为0的边。

每个国家的入点向出点连一条上下界均为该国家访问人数费用为0的边。

每个国家的出点向汇点连一条上界为正无穷下界为0费用为0的边。

对于国家i能到国家j,i的出点向j的入点连一条上界为正无穷下界为0费用为机票费的边。

然后对图求一边有源汇上下界最小费用可行流即可得出最小费用。

具体做法是先将所有边的下界乘费用相加,这一部分是必须的费用,然后按照“有源汇上下界可行流”建图,从超级源向超级汇跑一遍最小费用最大流,两个费用相加即为答案。

至于本题本身的建图思路,与bzoj1927星际竞速类似,下面放一份十分良心的题解。

天地良心无与伦比谁与争锋的一篇题解

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<queue>
 6 using namespace std;
 7 const int dian=305;
 8 const int bian=100005;
 9 const int INF=0x3f3f3f3f;
10 int h[dian],nxt[bian],ver[bian],val[bian],cos[bian];
11 int d[dian],v[dian],with[dian],minn[dian];
12 int in[dian],out[dian];
13 int n,m,tot,aa,mf;
14 int S,T,SS,TT;
15 void add(int a,int b,int c,int d,int e){
16     tot++;ver[tot]=b;val[tot]=d-c;cos[tot]=e;nxt[tot]=h[a];h[a]=tot;
17     tot++;ver[tot]=a;val[tot]=0;cos[tot]=-e;nxt[tot]=h[b];h[b]=tot;
18     in[b]+=c,out[a]+=c;
19     mf+=c*e;
20 }
21 bool tell(){
22     memset(v,0,sizeof(v));
23     memset(d,0x3f,sizeof(d));
24     memset(with,0,sizeof(with));
25     memset(minn,0x3f,sizeof(minn));
26     queue<int>q;
27     q.push(S);
28     v[S]=1;
29     d[S]=0;
30     while(!q.empty()){
31         int x=q.front();
32         q.pop();
33         v[x]=0;
34         for(int i=h[x];i;i=nxt[i]){
35             int y=ver[i];
36             if(d[y]>d[x]+cos[i]&&val[i]){
37                 d[y]=d[x]+cos[i];
38                 minn[y]=min(minn[x],val[i]);
39                 with[y]=i;
40                 if(!v[y]){
41                     v[y]=1;
42                     q.push(y);
43                 }
44             }
45         }
46     }
47     if(d[T]==0x3f3f3f3f)
48         return false;
49     return true;
50 }
51 int zeng(){
52     for(int i=T;i!=S;i=ver[with[i]^1]){
53         val[with[i]]-=minn[T];
54         val[with[i]^1]+=minn[T];
55     }
56     return minn[T]*d[T];
57 }
58 int dinic_cost(){
59     int r=0;
60     while(tell())
61         r+=zeng();
62     return r;
63 }
64 int main(){
65     memset(h,0,sizeof(h));
66     memset(nxt,0,sizeof(nxt));
67     memset(in,0,sizeof(in));
68     memset(out,0,sizeof(out));
69     tot=1,mf=0;
70     scanf("%d%d",&n,&m);
71     SS=n+n+2,TT=n+n+3,S=n+n+4,T=n+n+5;
72     add(SS,n+n+1,0,m,0);
73     for(int i=1;i<=n;i++)
74         add(n+n+1,i,0,INF,0);
75     for(int i=1;i<=n;i++)
76         add(n+i,TT,0,INF,0);
77     for(int i=1;i<=n;i++){
78         scanf("%d",&aa);
79         add(i,n+i,aa,aa,0);
80     }
81     for(int i=1;i<n;i++)
82         for(int j=1;j<=n-i;j++){
83             scanf("%d",&aa);
84             if(aa!=-1)
85                 add(n+i,i+j,0,INF,aa);
86         }
87     add(TT,SS,0,INF,0);
88     for(int i=1;i<=TT;i++){
89         if(in[i]>out[i])
90             add(S,i,0,in[i]-out[i],0);
91         else if(out[i]>in[i])
92             add(i,T,0,out[i]-in[i],0);
93     }
94     printf("%d",mf+dinic_cost());
95     return 0;
96 }

注意题意叙述不清,每个人可以从任意一个国家开始走。

时间: 2024-10-18 18:36:07

bzoj 2055 80人环游世界的相关文章

bzoj 2055: 80人环游世界 -- 上下界网络流

2055: 80人环游世界 Time Limit: 10 Sec  Memory Limit: 64 MB Description 想必大家都看过成龙大哥的<80天环游世界>,里面的紧张刺激的打斗场面一定给你留下了深刻的印象.现在就有这么 一个80人的团伙,也想来一次环游世界. 他们打算兵分多路,游遍每一个国家. 因为他们主要分布在东方,所以他们只朝西方进军.设从东方到西方的每一个国家的编号依次为1...N.假若第i个人的游历路线为P1.P2......Pk(0≤k≤N),则P1<P2&

BZOJ 2055 80人环游世界 有上下界的费用流

题目大意:给定n个点,每个点有固定的经过次数,m个人从任意节点出发任意节点结束,只能向右走,要求总边权和最小 有源汇.有上下界的费用流 其实上下界费用流有两种写法- - 一种是按照上下界网络流那么转化- - 一种是把必经边的费用减掉一个INF 跑完再加回去 我比较倾向于第一种写法- - 第二种写法在INF的取值上有点麻烦- - #include <cstdio> #include <cstring> #include <iostream> #include <al

【BZOJ-2055】80人环游世界 上下界费用流 (无源无汇最小费用最大流)

2055: 80人环游世界 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 321  Solved: 201[Submit][Status][Discuss] Description 想必大家都看过成龙大哥的<80天环游世界>,里面的紧张刺激的打斗场面一定给你留下了深刻的印象.现在就有这么 一个80人的团伙,也想来一次环游世界. 他们打算兵分多路,游遍每一个国家. 因为他们主要分布在东方,所以他们只朝西方进军.设从东方到西方的每一个国家的编号依次为

【bzoj2055】80人环游世界 有上下界费用流

原文地址:http://www.cnblogs.com/GXZlegend 题目描述 想必大家都看过成龙大哥的<80天环游世界>,里面的紧张刺激的打斗场面一定给你留下了深刻的印象.现在就有这么 一个80人的团伙,也想来一次环游世界. 他们打算兵分多路,游遍每一个国家. 因为他们主要分布在东方,所以他们只朝西方进军.设从东方到西方的每一个国家的编号依次为1...N.假若第i个人的游历路线为P1.P2......Pk(0≤k≤N),则P1<P2<......<Pk. 众所周知,中

bzoj千题计划159:bzoj2055: 80人环游世界(上下界费用流)

http://www.lydsy.com/JudgeOnline/problem.php?id=2055 某个国家必须经过vi次, 可以转化为上下界都为vi的边 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define N 205 #define M 10500 const int inf=1e9; int sr

BZOJ2055 80人环游世界

m个人随便设定起点= =,所以是有上下界网络流喽... 今天刚学,于是试着写了写,1A耶! 费用流是板子哦~ 1 /************************************************************** 2 Problem: 2055 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:536 ms 7 Memory:8624 kb 8 ******************************

[bzoj2055]80人环游世界[网络流,上下界网络流]

手动画了整张图,,算是搞懂了吧,, 1 #include <bits/stdc++.h> 2 3 #define INF 0x3f3f3f3f 4 5 using namespace std; 6 7 template<const int _n,const int _m> 8 struct Edge 9 { 10 struct Edge_base { int to,next,w,c; }e[_m]; int cnt,p[_n]; 11 Edge() { clear(); } 12

bzoj2055: 80人环游世界(可行流)

传送门 表示完全看不懂最小费用可行流…… 据某大佬说 我们考虑拆点,然后进行如下连边 $s$向$a_i$连边,权值$0$,容量$[0,m]$ $a_i$向$a_i'$连边,权值$0$容量$[v_i,v_i]$ 如果存在边$(i,j)$,则连边$a_i'->a_i$,权值为$w_{i,j}$,容量$[0,m]$ $a_i'$向$t$连边,权值$0$,容量$[0,m]$ $t$向$t'$连边,权值$0$容量$[0,m]$ 然后跑个最小费用可行流 1 //minamoto 2 #include<io

P4553 80人环游世界 上下界费用流

题意: 有1-n个城市  有m个人去旅游  每个人只能从编号小的城市到编号大的城市  花费费用为COSTij   一开始每个人可以从任意一个城市开始旅行   且每个城市恰好有Vi个人经过(一开始也算经过) 问最小花费 显然用有上下界的费用流非常好理解  每个点进行拆点 两点之间连上界和下界都为Vi 表示正好通过Vi人      然后经典连图即可 再控制一下人数m  跑模板 (正面建图) #include<bits/stdc++.h> using namespace std; //input b