【有源汇上下界费用流】BZOJ 3876 [Ahoi2014]支线剧情
题目链接:
http://www.lydsy.com:808/JudgeOnline/problem.php?id=3876
题目大意:
给定一张拓扑图(有向无环图),每条边有边权,每次只能从第一个点出发沿着拓扑图走一条路径,求遍历所有边所需要的最小边权和。
题目思路:
【有源汇上下界费用流】
Orz两位神犇,以下思路借鉴自
http://hzwer.com/6224.html
http://blog.csdn.net/popoqqq/article/details/43024221
建图如下:
设汇t,源s=1,超级源S,超级汇T。
本质是每条边的下界为1,上界为MAX,跑一遍有源汇的上下界最小费用最小流。(因为上界无穷大,所以只要满足所有下界的最小费用最小流)
对每个点x:
从x到t连一条费用为0,流量为MAX的边,表示可以任意停止当前的剧情(接下来的剧情从更优的路径去走,画个样例就知道了)
对于每一条边权为z的边x->y:
从S到y连一条流量为1,费用为z的边,代表这条边至少要被走一次。
从x到y连一条流量为MAX,费用为z的边,代表这条边除了至少走的一次之外还可以随便走。
从x到T连一条流量为1,费用为0的边。(注意是每一条x->y的边都连,或者你可以记下x的出边数Kx,连一次流量为Kx,费用为0的边)。
建完图后从S到T跑一遍费用流,即可。(当前跑出来的就是满足上下界的最小费用最小流了)
1 // 2 //by coolxxx 3 // 4 #include<iostream> 5 #include<algorithm> 6 #include<string> 7 #include<iomanip> 8 #include<memory.h> 9 #include<time.h> 10 #include<stdio.h> 11 #include<stdlib.h> 12 #include<string.h> 13 #include<stdbool.h> 14 #include<math.h> 15 #define min(a,b) ((a)<(b)?(a):(b)) 16 #define max(a,b) ((a)>(b)?(a):(b)) 17 #define abs(a) ((a)>0?(a):(-(a))) 18 #define lowbit(a) (a&(-a)) 19 #define sqr(a) (a)*(a) 20 #define swap(a,b) (a)^=(b),(b)^=(a),(a)^=(b) 21 #define eps 1e-8 22 #define MAX 0x7f7f7f7f 23 #define INF 20000 24 #define PI 3.1415926535897 25 #define N 304 26 #define M 5004 27 using namespace std; 28 int n,m,cas,lll,ans; 29 int last[N],d[N]; 30 int S,T,s,t,qq[M+M]; 31 bool K; 32 bool mark[N]; 33 struct data 34 { 35 int to,from,next,f,c; 36 }e[M*10]; 37 inline int Read() 38 { 39 int x=0,f=1;char ch=getchar(); 40 while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();} 41 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 42 return x*f; 43 } 44 void add(int u,int f,int w,int c) 45 { 46 e[++lll].to=f;e[lll].from=u; 47 e[lll].next=last[u];last[u]=lll; 48 e[lll].f=w;e[lll].c=c; 49 } 50 void link(int u,int v,int w,int c) 51 { 52 add(u,v,w,c); 53 add(v,u,0,-c); 54 } 55 void build() 56 { 57 int i,j,x,y,z; 58 memset(last,0,sizeof(last)); 59 lll=1;ans=0; 60 s=1,t=n+1; 61 S=n+2,T=n+3; 62 for(i=1;i<=n;i++) 63 { 64 j=Read(); 65 link(i,t,MAX,0); 66 while(j--) 67 { 68 y=Read();z=Read(); 69 link(i,y,MAX,z); 70 link(S,y,1,z); 71 link(i,T,1,0); 72 } 73 } 74 link(t,s,MAX,0); 75 } 76 bool spfa(int S,int T) 77 { 78 int i,now; 79 memset(mark,0,sizeof(mark)); 80 memset(d,0x7f,sizeof(d)); 81 int head=M-1,tail=M; 82 qq[M]=T; 83 d[T]=0;mark[T]=1; 84 while(head++<tail) 85 { 86 now=qq[head]; 87 for(i=last[now];i;i=e[i].next) 88 { 89 if(e[i^1].f>0 && d[now]-e[i].c<d[e[i].to]) 90 { 91 d[e[i].to]=d[now]-e[i].c; 92 if(!mark[e[i].to]) 93 { 94 if(d[e[i].to]<d[qq[head]]) 95 qq[head--]=e[i].to; 96 else 97 qq[++tail]=e[i].to; 98 mark[e[i].to]=1; 99 } 100 } 101 } 102 mark[now]=0; 103 } 104 if(d[S]==MAX)return 0; 105 else return 1; 106 } 107 int dfs(int u,int f,int T) 108 { 109 int v,i,tt,asp=0; 110 if(u==T) 111 { 112 K=1; 113 return f; 114 } 115 mark[u]=1; 116 for(i=last[u];i;i=e[i].next) 117 { 118 if(!mark[e[i].to] && e[i].f>0 && d[u]-e[i].c==d[e[i].to]) 119 { 120 tt=dfs(e[i].to,min(e[i].f,f-asp),T); 121 e[i].f-=tt; 122 e[i^1].f+=tt; 123 ans+=tt*e[i].c; 124 asp+=tt; 125 if(asp==f) 126 return f; 127 } 128 } 129 return asp; 130 } 131 void mincostflow(int S,int T) 132 { 133 while(1) 134 { 135 if(!spfa(S,T))break; 136 K=1; 137 while(K) 138 { 139 K=0; 140 memset(mark,0,sizeof(mark)); 141 dfs(S,MAX,T); 142 } 143 } 144 } 145 int main() 146 { 147 #ifndef ONLINE_JUDGE 148 // freopen("1.txt","r",stdin); 149 // freopen("2.txt","w",stdout); 150 #endif 151 int i,j; 152 while(~scanf("%d",&n) && n) 153 { 154 build(); 155 mincostflow(S,T); 156 printf("%d\n",ans); 157 } 158 return 0; 159 } 160 161 162 /* 163 // 164 165 // 166 */