题目要求即为每条边至少经过一次,那么就想到有下界网络流(上界为正无穷),每条边的流量就代表经过了几次。建立一个源点和汇点,从源点连向 (1) 一条下界为 (0) 的边,从每个点连向汇点一条下界为 (0) 的边,应为还要求时间最短所以是上下界最小费用流。套模板即可。
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
template<typename T>void read(T &x){
T flag=1;
char ch=getchar();
for(;'0'>ch||ch>'9';ch=getchar()){
if(ch=='-')flag=-1;
}
for(x=0;'0'<=ch&&ch<='9';ch=getchar()){
x=x*10+ch-'0';
}
}
struct node{
int pre,to,val,cost;
}edge[100005];
int head[100005],tot=1;
int s, t;
int S,T;
int n;
int dis[100005];
bool vis[100005];
int pre[100005], incf[100005];
bool spfa() {
queue<int> q;
memset(dis, 0x3f, sizeof(dis));
memset(vis, 0, sizeof(vis));
dis[s] = 0;
vis[s] = 1;
q.push(s);
incf[s] = inf;
while (!q.empty()) {
int x = q.front(); q.pop();
for (int i = head[x]; i; i = edge[i].pre) {
if (!edge[i].val) continue;
int y = edge[i].to;
if (dis[y] > dis[x] + edge[i].cost) {
dis[y] = dis[x] + edge[i].cost;
incf[y] = min(incf[x], edge[i].val);
pre[y] = i;
if (!vis[y]) {
vis[y] = 1;
q.push(y);
}
}
}
vis[x] = 0;
}
if (dis[t] < 0x3f3f3f3f) return true;
return false;
}
int max_flow, ans;
void update() {
int x = t;
while (x != s) {
int i = pre[x];
edge[i].val -= incf[t];
edge[i ^ 1].val += incf[t];
x = edge[i ^ 1].to;
}
max_flow += incf[t];
ans += dis[t] * incf[t];
}
void add_edge(int u,int v,int l,int w){
edge[++tot]=node{head[u],v,l,w};
head[u]=tot;
edge[++tot]=node{head[v],u,0,-w};
head[v]=tot;
}
struct node2{
int x,y,low,lim,cost;
}edge2[10005];
int tot2;
void add_edge2(int u,int v,int l,int r,int w) {
edge2[++tot2]=node2{u,v,l,r,w};
}
int flow[10005];
int main(){
S=0,T=n+1;
read(n);
add_edge2(0,S,0,inf,0);
for(int i=1,k;i<=n;i++){
read(k);
for(int j=1,v,w;j<=k;j++){
read(v);read(w);
add_edge2(i,v,1,inf,w);
}
add_edge2(i,T,0,inf,0);
}
add_edge2(T, S, 0, inf, 0);
s=n+2,t=n+3;
for (int i = 1; i <= tot2; i++) {
int x=edge2[i].x,y = edge2[i].y;
flow[x]-=edge2[i].low;
flow[y]+=edge2[i].low;
edge2[i].lim-=edge2[i].low;
ans+=edge2[i].low * edge2[i].cost;
add_edge(x, y, edge2[i].lim, edge2[i].cost);
}
for (int i = 0; i <= n+1; i++) {
if (flow[i] > 0) {
add_edge(s, i, flow[i], 0);
} else if (flow[i] < 0) {
add_edge(i, t, -flow[i], 0);
}
}
while (spfa()) {
update();
}
printf("%d
", ans);
return 0;
}