洛谷 P1344 [USACO4.4]追查坏牛奶Pollutant Control(最大流最小割定理)

该博客介绍了USACO题目[USACO4.4]追查坏牛奶Pollutant Control,涉及如何在保证坏牛奶不送到零售商的前提下,通过最大流最小割定理来确定最小经济损失的运输卡车停运方案。博客内容包含问题描述、输入输出格式、样例及解题提示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[USACO4.4]追查坏牛奶Pollutant Control

题目描述

你第一天接手三鹿牛奶公司就发生了一件倒霉的事情:公司不小心发送了一批有三聚氰胺的牛奶。很不幸,你发现这件事的时候,有三聚氰胺的牛奶已经进入了送货网。这个送货网很大,而且关系复杂。你知道这批牛奶要发给哪个零售商,但是要把这批牛奶送到他手中有许多种途径。送货网由一些仓库和运输卡车组成,每辆卡车都在各自固定的两个仓库之间单向运输牛奶。在追查这些有三聚氰胺的牛奶的时候,有必要保证它不被送到零售商手里,所以必须使某些运输卡车停止运输,但是停止每辆卡车都会有一定的经济损失。你的任务是,在保证坏牛奶不送到零售商的前提下,制定出停止卡车运输的方案,使损失最小。

输入格式

第一行: 两个整数N(2<=N<=32)、M(0<=M<=1000), N表示仓库的数目,M表示运输卡车的数量。仓库1代 表发货工厂,仓库N代表有三聚氰胺的牛奶要发往的零售商。 第2…M+1行: 每行3个整数Si,Ei,Ci。其中Si,Ei表示这 辆卡车的出发仓库,目的仓库。Ci(0 <= C i <= 2,000,000) 表示让这辆卡车停止运输的损失。

输出格式

两个整数C、T:C表示最小的损失,T表示在损失最小的前提下,最少要停止的卡车数。

样例 #1

样例输入 #1

4 5
1 3 100
3 2 50
2 4 60
1 2 40
2 3 80

样例输出 #1

60 1

提示

题目翻译来自NOCOW。

USACO Training Section 4.4

1、 最大流 = 最小割
2、 用 dinic 算法求出最大流
3、 然后剩下的残留网络, 将正边 edge[i] = 0 的边重新置值 为1, 正边不为0 的边重新重新置值inf
	所有的反边 edge[i ^ 1] 置值为0。
	重新跑一边 dinic ,得到的最大流就是 最小割的边数。
4、 样例 11 输入的边号 x, y 可能大于 n, 因此 每次输入 x, y ,都 n = max(n, max(x, y));
#include <bits/stdc++.h>
using namespace std;
const int N = 4010, M = 4010, inf = 2147483647;
int n, m;
int now[N];	//当前弧优化
int head[N], ver[M], edge[M], Next[M];
int s, t, tot, maxflow;
int d[N];
int a[N], b[N];	// 存边


void add(int x, int y, int z)
{
	ver[++tot] = y, edge[tot] = z, Next[tot] = head[x], head[x] = tot;
}

bool bfs()
{
	memset(d, 0, sizeof d);
	queue<int> q;
	q.push(s); d[s] = 1; now[s] = head[s];
	while(q.size())
	{
		int x = q.front(); q.pop();
		for(int i = head[x]; i; i = Next[i])
		{
			int y = ver[i];
			if(edge[i] && !d[y])
			{
				q.push(y);
				now[y] = head[y];
				d[y] = d[x] + 1;
				if(y == t)
					return true;
			}
		}
	}
	return false;
}



int dfs(int x, int flow)
{
	if(x == t)
		return flow;
	int rest = flow, k, i;
	for(i = now[x]; i && rest; i = Next[i])
	{
		int y = ver[i];
		if(edge[i] && d[y] == d[x] + 1)
		{
			k = dfs(y, min(rest, edge[i]));
			if(!k)
				d[y] = 0;
			edge[i] -= k;
			edge[i ^ 1] += k;
			rest -= k;
		}
	}
	now[x] = i;
	return flow - rest;
}

int dinic()
{
	int ans = 0;
	while(bfs())
	{
		ans += dfs(s, inf);
	}
	return ans;
}

int main()
{
	scanf("%d%d", &n, &m);
	s = 1, t = n;
	tot = 1;
	int x, y, z;
	for(int i = 0; i < m; ++i)
	{
		scanf("%d%d%d", &x, &y, &z);	
		a[i] = x, b[i] = y;
		n = max(n, max(x, y));
		add(x, y, z), add(y, x, 0);
	}
	t = n;
	// 最大流
	printf("%d ", dinic());
	for(int i = 2; i <= tot; i += 2)
	{
		if(!edge[i])
			edge[i] = 1;
		else
			edge[i] = inf;
		edge[i + 1] = 0;
	}
	printf("%d\n", dinic());
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值