原图所有边下界设为1上界设为inf花费为时间,那么显然就是一个上下界最小费用流了。做法与可行流类似。
因为每次选的都是最短路增广,且显然不会有负权增广路,所以所求出来的可行流的费用就是最小的。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define N 310
#define M 20010
#define inf 100000000
#define S 0
#define T 301
int n,p[N],t=-,pre[N],q[N],d[N],degree[N],ans=;
bool flag[N];
struct data{int to,nxt,cap,flow,cost;
}edge[M];
void addedge(int x,int y,int z,int cost)
{
t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].cap=z,edge[t].flow=,edge[t].cost=cost,p[x]=t;
t++;edge[t].to=x,edge[t].nxt=p[y],edge[t].cap=,edge[t].flow=,edge[t].cost=-cost,p[y]=t;
}
int inc(int &x){x++;if (x>n+) x-=n+;return x;}
bool spfa()
{
memset(d,,sizeof(d));d[S]=;
memset(flag,,sizeof(flag));
int head=,tail=;q[]=S;
do
{
int x=q[inc(head)];flag[x]=;
for (int i=p[x];~i;i=edge[i].nxt)
if (d[x]+edge[i].cost<d[edge[i].to]&&edge[i].flow<edge[i].cap)
{
d[edge[i].to]=d[x]+edge[i].cost;
pre[edge[i].to]=i;
if (!flag[edge[i].to])
{
q[inc(tail)]=edge[i].to;
flag[edge[i].to]=;
}
}
}while (head!=tail);
return d[T]<inf;
}
void ekspfa()
{
while (spfa())
{
int v=inf;
for (int i=T;i!=S;i=edge[pre[i]^].to)
v=min(v,edge[pre[i]].cap-edge[pre[i]].flow);
for (int i=T;i!=S;i=edge[pre[i]^].to)
ans+=v*edge[pre[i]].cost,edge[pre[i]].flow+=v,edge[pre[i]^].flow-=v;
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj3876.in","r",stdin);
freopen("bzoj3876.out","w",stdout);
const char LL[]="%I64d";
#else
const char LL[]="%lld";
#endif
n=read();
memset(p,,sizeof(p));
for (int i=;i<=n;i++)
{
int k=read();
if (i>) addedge(i,,inf,);
while (k--)
{
int x=read(),y=read();
addedge(i,x,inf,y);
degree[i]++;degree[x]--;
ans+=y;
}
}
for (int i=;i<=n;i++)
if (degree[i]>) addedge(i,T,degree[i],);
else if (degree[i]<) addedge(S,i,-degree[i],);
ekspfa();
cout<<ans;
return ;
}