点击这里查看原题
本题是有源汇上下界最小费用流,具体建图如下:
- 从每个点u向它能到达的点v连容量inf费用为w的边,从s’向v连容量1费用w的边,从u向t’连容量1费用0的边
- 从每个非根的点u向t连容量inf费用0的边(因为随时可以跳出这段剧情)
- 从t向s连容量inf费用0的边
#include<bits/stdc++.h>
#define ll long long
#define inf 99999999
using namespace std;
const int M=305;
int n,fir[M],tot=1,dis[M],s,t,ans;
bool vis[M];
struct edge{
int v,w,c,nex;
}e[90005];
void add(int u,int v,int w,int c){
e[++tot]=(edge){v,w,c,fir[u]};
fir[u]=tot;
e[++tot]=(edge){u,0,-c,fir[v]};
fir[v]=tot;
}
bool spfa(int s,int t){
memset(vis,0,sizeof(vis));
memset(dis,127,sizeof(dis));
dis[t]=0;
vis[t]=1;
queue<int> q;
q.push(t);
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=fir[u];i;i=e[i].nex){
int v=e[i].v;
if(e[i^1].w&&dis[v]>dis[u]+e[i^1].c){
dis[v]=dis[u]+e[i^1].c;
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
}
return dis[s]<inf;
}
int dfs(int u,int f,int t){
vis[u]=1;
if(u==t) return f;
int sum=0;
for(int i=fir[u];i;i=e[i].nex){
int v=e[i].v;
if(!vis[v]&&e[i].w&&dis[u]-e[i].c==dis[v]){
int d=dfs(v,min(f,e[i].w),t);
sum+=d;
f-=d;
ans+=d*e[i].c;
e[i].w-=d;
e[i^1].w+=d;
if(!f) return sum;
}
}
return sum;
}
void zkw(int s,int t){
while(spfa(s,t)){
vis[t]=1;
while(vis[t]){
memset(vis,0,sizeof(vis));
dfs(s,inf,t);
}
}
}
int main(){
scanf("%d",&n);
s=n+2,t=n+3;
for(int i=1;i<=n;i++){
int m;
scanf("%d",&m);
if(i!=1) add(i,n+1,inf,0);
while(m--){
int v,c;
scanf("%d%d",&v,&c);
add(i,v,inf,c);
add(s,v,1,c);
add(i,t,1,0);
}
}
add(n+1,1,inf,0);
zkw(s,t);
printf("%d\n",ans);
return 0;
}