usaco --4.4.2--Pollutant Control

一道网络流的题,求出最大流,然后求出最小割的最小的边数,还要输出最小割字典序最小的一组;

正儿八经的写的第一道网络流的题目吧,进步蛮大的。

基本思路是,先求出最大流,然后枚举每一条边,删除这条边后求最大流,如果求出的最大流加上被删除变的容量等于没有删除任何边的最大流,就说明这条边属于最小割,输出之,注意输出的时候记录下已经输出了多少条边了,输完了就退出,不然会多输出,至于为什么可以先知道最小割有多少条边,参考nocow题解那个c×1001+1,

by the way ,如果看不到数据的话,真不知道要debug多久。能看到数据的话就得记住错在了什么地方,下次看不到数据的时候才有debug的方向.

注意:有重边,容量用Long long 存储。

#include<iostream>
#include<fstream>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cstdio>
#define maxn 40
#define maxm 1200
#define M(a) memset((a),0,sizeof((a)))
#define zout cout
using namespace std;
ifstream fin("milk6.in");
ofstream fout("milk6.out");
struct Edge
{
	long long from,to,cap,flow,num,ag;
};
bool vis[maxn];
int d[maxn];
vector<Edge> edge;
int cur[maxn];
vector<int> g[maxn];
int n,m,s,t;
bool init()
{
	if(fin>>n>>m)
	{
		edge.clear();
		int x,y,w;
		for(int i=1;i<=m;i++)
		{
			fin>>x>>y>>w;
			w=w*1001+1;
			edge.push_back((Edge){
				x,y,w,0,i,0
			});
			edge.push_back((Edge){
				y,x,0,0,0,0
			});
			int ln=edge.size();
			g[x].push_back(ln-2);
			g[y].push_back(ln-1);
		}
		s=1;t=n;
		return true;
	}
	return false;
}
bool bfs()
{
	M(vis);
	queue<int> q;
	d[s]=0;
	q.push(s);
	vis[s]=1;
	while(!q.empty())
	{
		int u=q.front();q.pop();
		int ln=g[u].size();
		for(int i=0;i<ln;i++)
		{
			Edge &e =edge[g[u][i]];
			if(e.ag)continue;
			if(!vis[e.to]&&e.cap>e.flow)
			{
				vis[e.to]=1;
				d[e.to]=d[u]+1;
				q.push(e.to);
			}
		}
	}
	return vis[t];
}
long long dfs(int u,long long a)
{
	if(u==t||a==0)return a;
	long long flow=0,f;
	for(int & i= cur[u];i<g[u].size();i++)
	{
		Edge &e = edge[g[u][i]];
		if(e.ag)continue;
		if(d[u]+1==d[e.to])
		{
			if(a==-1)
			{
				f=dfs(e.to,e.cap-e.flow);
			}
			else
			{
				f=dfs(e.to,min(a,e.cap-e.flow));
			}
			if(f>0)
			{
				flow+=f;
				e.flow+=f;
				edge[g[u][i]^1].flow-=f;
				if(a>0)
				a-=f;
			}
		}
	}
	return flow;
}
long long cal_flow()
{
	long long flow=0;
	int ln=edge.size();
	for(int i=0;i<ln;i++)
	edge[i].flow=0;
	while(bfs())
	{
		M(cur);
		flow+=dfs(s,-1);
	}
	return flow;
}
void slove()
{
	long long max_flow=cal_flow();
	long long temp_flow;
	zout<<max_flow/1001<<" "<<max_flow%1001<<endl;
	int ln=edge.size();
	int calu=max_flow%1001;
	for(int i=0;calu&&i<ln;i++)
	{
		Edge &e = edge[i];
		if(e.num)
		{
			edge[i].ag=1;
			edge[i^1].ag=1;
			temp_flow=cal_flow();
			if(temp_flow+e.cap==max_flow)
			{
				calu--;
				zout<<e.num<<endl;
			}
			edge[i].ag=0;
			edge[i^1].ag=0;
		}
	}
}
int main()
{
	while(init())
	slove();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值