【bzoj3876】 Ahoi2014—支線劇情

http://www.lydsy.com/JudgeOnline/problem.php?id=3876 (題目連接)php

題意

  給出一張拓撲圖,每條邊有一個權值,問每次從1號點出發,走遍全部的邊所須要的最小花費是多少。ios

Solution

  上下界最小費用可行流。網絡

  由於每條邊至少要被通過一次,因此每條邊有個流量下界1。又由於每一個節點均可以做爲結束點,那麼每一個節點都有可能成爲匯點,因此每一個點都要向源點1連一條容量爲無窮費用爲0的邊。spa

  這樣套上上下界網絡流的模型,求解費用最小的可行流便可。blog

細節

  邊數$n^2$get

代碼

// bzoj3876
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define LL long long
#define inf (1ll<<30)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
using namespace std;

const int maxn=1010;
int cnt=1,n,head[maxn],S,T,ans;
int vis[maxn],dis[maxn],f[maxn],p[maxn];

struct edge {int from,to,next,w,c;}e[maxn*maxn];
									 
void link(int u,int v,int w,int c) {
	e[++cnt]=(edge){u,v,head[u],w,c};head[u]=cnt;
	e[++cnt]=(edge){v,u,head[v],0,-c};head[v]=cnt;
}
bool SPFA() {
	for (int i=S;i<=T;i++) dis[i]=inf;
	queue<int> q;q.push(S);dis[S]=0;f[S]=inf;
	while (!q.empty()) {
		int x=q.front();q.pop();
		vis[x]=0;
		for (int i=head[x];i;i=e[i].next) if (e[i].w && dis[e[i].to]>dis[x]+e[i].c) {
				dis[e[i].to]=dis[x]+e[i].c;
				f[e[i].to]=min(f[x],e[i].w);
				p[e[i].to]=i;
				if (!vis[e[i].to]) q.push(e[i].to),vis[e[i].to]=1;
			}
	}
	if (dis[T]==inf) return 0;
	for (int i=p[T];i;i=p[e[i].from]) e[i].w-=f[T],e[i^1].w+=f[T];
	ans+=dis[T]*f[T];
	return 1;
}
int main() {
	scanf("%d",&n);
	S=0,T=n+1;
	for (int k,i=1;i<=n;i++) {
		scanf("%d",&k);
		for (int x,y,j=1;j<=k;j++) {
			scanf("%d%d",&x,&y);
			link(i,x,inf,y);
			link(S,x,1,y);
		}
		link(i,T,k,0);
		if (i!=1) link(i,1,inf,0);
	}
	while (SPFA());
	printf("%d",ans);
	return 0;
}
相關文章
相關標籤/搜索