【bzoj3876】 Ahoi2014—支线剧情

时间:2023-09-11 20:30:44

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

题意

  给出一张拓扑图,每条边有一个权值,问每次从1号点出发,走遍所有的边所需要的最小花费是多少。

Solution

  上下界最小费用可行流。

  因为每条边至少要被经过一次,所以每条边有个流量下界1。又因为每个节点都可以作为结束点,那么每个节点都有可能成为汇点,所以每个点都要向源点1连一条容量为无穷费用为0的边。

  这样套上上下界网络流的模型,求解费用最小的可行流即可。

细节

  边数$n^2$

代码

// 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;
}