CCF201812-5 管道清洁 题解(最小费可行流)

CCF201812-5 管道清洁 题解(最小费可行流)_第1张图片
无源汇的最小费可行流。
需要清洁的管道下界为1,不需要清洁的管道下界为0。
可重复经过的管道上界为正无穷,不可重复经过的管道上界为1。
然后建图直接跑最小费用流。

AC代码:

#include
#include
#include
using namespace std;
const int maxn = 233;
const int inf = 0x3f3f3f3f;
struct node{
	int u,v,f,w,nxt;
	node(){};
	node(int a,int b,int c,int d,int e):u(a),v(b),f(c),w(d),nxt(e){}
}e[maxn*maxn];
int cnt = 0;
int head[maxn];
void add(int u,int v,int f,int w){
	e[cnt] = node(u,v,f,w,head[u]);
	head[u] = cnt++;
	e[cnt] = node(v,u,0,-w,head[v]);
	head[v] = cnt++;
}
int st,ed,E,ex;
int n,m;
int du[maxn];
int sum;
int num = 0;
void init(){
	scanf("%d%d",&n,&m);
	st = 0;ed = n + 1;
	ex = n + 2;
	cnt = 0;
	sum = 0;
	num = 0;
	memset(head,-1,ex<<2);
	memset(du,0,ex<<2);
	while(m--){
		int u,v;char c[2];
		scanf("%d%d%s",&u,&v,c);
		if(c[0] == 'A'){
			add(u,v,inf,E);
			du[u]--;
			du[v]++;
			num+=E;
		}
		else if(c[0] == 'B'){
			du[u]--;
			du[v]++;
			num+=E;
		}
		else if(c[0] == 'C'){
			add(u,v,inf,E);
		}
		else add(u,v,1,E);
	}
	for(int i = 1;i <= n;++i){
		if(du[i] > 0){
			sum += du[i];
			add(st,i,du[i],0);
		}
		else if(du[i] < 0){
			add(i,ed,-du[i],0);
		}
	}
}
int pre[maxn];
int flow[maxn];
int inq[maxn];
int dis[maxn];
int spfa(){
	memset(pre,-1,ex<<2);
	memset(inq,0,ex<<2);
	memset(dis,0x3f,ex<<2);
	queue q;q.push(st);
	flow[st] = inf;inq[st] = 1;
	dis[st] = 0;
	while(q.size()){
		int u = q.front();q.pop();
		inq[u] = 0;
		for(int i = head[u];i != -1; i = e[i].nxt){
			int v = e[i].v;
			if(e[i].f && dis[v] > dis[u] + e[i].w){
				dis[v] = dis[u] + e[i].w;
				pre[v] = i;
				flow[v] = min(flow[u],e[i].f);
				if(!inq[v]) inq[v] = 1,q.push(v);
			}
		}
	}
	if(pre[ed] == -1) return -1;
	return flow[ed];
}
int mfmv(){
	int fw = 0;
	int ans = 0;
	int d;
	while((d = spfa())!=-1){
		fw += d;
		ans += dis[ed]*d;
		int v = ed;
		while(v!=st){
			e[pre[v]].f -= d;
			e[pre[v]^1].f += d;
			v = e[pre[v]].u;
		}
	}
	if(fw!=sum) return -1;
	return ans + num;
}
void sol(){
	int ans = mfmv();
	printf("%d\n",ans);
}
int main(){
	int T;cin>>T;cin>>E>>E;//输入的S没有用,不管它
	while(T--){
		init();sol();
	}
} 

你可能感兴趣的:(图论)