【bzoj3876】 Ahoi2014—支线剧情
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; }
This passage is made by MashiroSky.