[AHOI2014]支线剧情(有上下界的网络流)

题目要求即为每条边至少经过一次,那么就想到有下界网络流(上界为正无穷),每条边的流量就代表经过了几次。建立一个源点和汇点,从源点连向 (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;
}
原文地址:https://www.cnblogs.com/zcr-blog/p/14333272.html