#网络流,最小割#洛谷 1344 [USACO4.4]追查坏牛奶Pollutant Control

题目


分析

考虑答案求的是最小割,但是最小割的最小边数有点难求,
考虑建立双关键字,其实就是将边权赋值为原边权(*mx+1)
其中(mx)是一个比较大的数,不需要太大,
这样用网络流做之后对(mx)取模就是第二问的答案


代码

#include <cstdio>
#include <cctype>
#include <queue>
#define rr register
using namespace std;
const int N=41,M=10000; typedef long long lll;
const lll inf=1e18; lll ans;
struct node{int y; lll w; int next;}e[N*50];
int dis[N],v[N],n,m,S,T,et,as[N];
inline lll iut(){
	rr lll ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline bool bfs(int st){
	for (rr int i=1;i<=n;++i) dis[i]=0;
	rr queue<int>q; q.push(st),dis[st]=1;
	while (!q.empty()){
		rr int x=q.front(); q.pop();
		for (rr int i=as[x];i;i=e[i].next)
		if (e[i].w>0&&!dis[e[i].y]){
			dis[e[i].y]=dis[x]+1;
			if (e[i].y==T) return 1;
			q.push(e[i].y);
		}
	}
	return 0;
}
inline lll min(lll a,lll b){return a<b?a:b;}
inline lll dfs(int x,lll now){
	if (x==T||!now) return now;
	rr lll rest=0,f;
	for (rr int i=as[x];i;i=e[i].next)
	if (e[i].w>0&&dis[e[i].y]==dis[x]+1){
		f=dfs(e[i].y,min(now-rest,e[i].w)),
		rest+=f,e[i].w-=f,e[i^1].w+=f;
		if (now==rest) return now;
	}
	if (!rest) dis[x]=0;
	return rest;
}
signed main(){
	n=iut(),m=iut(),S=1,T=n,et=1;
	for (rr int i=1;i<=m;++i){
		rr int x=iut(),y=iut();
		rr lll w=iut()*M+1;
		e[++et]=(node){y,w,as[x]},as[x]=et;
		e[++et]=(node){x,0,as[y]},as[y]=et;
	}
	while (bfs(S)) ans+=dfs(S,inf);
	return !printf("%lld %lld",ans/M,ans%M);
}
原文地址:https://www.cnblogs.com/Spare-No-Effort/p/14110023.html