Pollutant Control

题意:不想写,摘抄NOCOW翻译(http://www.nocow.cn/index.php/Translate:USACO/milk6

描述

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

[编辑]格式

PROGRAM NAME: milk6

INPUT FORMAT:

(file milk6.in) 第一行: 两个整数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) 表示让这辆卡车停止运输的损失。


OUTPUT FORMAT:

(file milk6.out) 第1行两个整数C,T。C表示最小的损失,T表示要停止的最少卡车数。接下来T行表示你要停止哪几条线路。如果有多种方案使损失最小,输出停止的线路最少的方案。如果仍然还有相同的方案,请选择开始输入顺序最小的。

[编辑]SAMPLE INPUT

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

[编辑]SAMPLE OUTPUT

60 1
3


解题思路:

  1. 第一问比较简单,求一下有向图的最大流,那么最小割就等于最大流
  2. 第二问需要求最小割的边集,比较复杂,参考了“北极天南星”的解题报告。大意是将边集按费用降序排序(费用相同的保持在输入中的出现先后次序),然后从头到尾开始贪心每一条边,如果边的费用<目前最大流而且边在最小割边集中,那么将其纳入结果,并且将目前最大流减去该边的费用。循环直到目前最大流为0则得到全部结果
  3. 如何确定边在最小割边集中:将该边(设容量为a)删去,计算最大流b,如果原最大流c满足c = a + b,则该边在最小割边集中

代码

/*
ID: zc.rene1
LANG: C
PROG: milk6
 */

#include<stdio.h>
#include<stdlib.h>
#include<string.h> 

#define INFINITY 2000000000
int N, M;
int capacity[33][33];
int capacity_cp[33][33];
int edge[1001][4];
int visited[33];
int result[1001];
int result_num;

void GetInput(FILE *fin)
{
    int i, p1, p2, cost;

    memset(capacity, 0, 33 * 33 * sizeof(int));

    fscanf(fin, "%d %d", &N, &M);
    for (i=1; i<=M; i++)
    {
	fscanf(fin, "%d %d %d", &p1, &p2, &cost);
	capacity[p1][p2] += cost;
	edge[i][0] = p1;
	edge[i][1] = p2;
	edge[i][2] = cost;
	edge[i][3] = i;
    }
}

int MaxFlow(int source, int sink)
{
    int flow[33];
    int visited[33];
    int prevnode[33];
    int i, max_flow, max_loc, temp, path_capacity, current, next;
    int total_flow;

    if (source == sink)
    {
	total_flow = INFINITY;	
	return ;
    }

    total_flow = 0;
    while (1)
    {
	for (i=1; i<=N; i++)
	{
	    flow[i] = 0;
	    prevnode[i] = 0;
	    visited[i] = 0;
	}
	flow[source] = INFINITY;

	while (1)
	{
	    max_flow = 0;
	    max_loc = 0;

	    for (i=1; i<=N; i++)
	    {
		if (visited[i] == 0 && flow[i] > max_flow)
		{
		    max_flow = flow[i];
		    max_loc = i;
		}
	    }
	    
	    if (max_loc == 0)
	    {
		break;
	    }
	    if (max_loc == sink)
	    {
		break;
	    }

	    visited[max_loc] = 1;

	    for (i=1; i<=N; i++)
	    {
		if (capacity_cp[max_loc][i] > 0)
		{
		    temp = max_flow < capacity_cp[max_loc][i] ? max_flow : capacity_cp[max_loc][i];
		    if (flow[i] < temp)
		    {
			flow[i] = temp;
			prevnode[i] = max_loc;
		    }
		}
	    }
	}

	if (max_loc == 0)
	{
	    break;
	}

	path_capacity = flow[sink];
	total_flow += path_capacity;


	current = sink;

	while (current != source)
	{
	    next = prevnode[current];

	    capacity_cp[next][current] -= path_capacity;
	    capacity_cp[current][next] += path_capacity;

	    current = next;
	}
    }

    return total_flow;
}

void SortEdge(void)
{
    int temp[4];
    int i, j;

    for (j=M; j>0; j--)
    {
	for (i=1; i<j; i++)
	{
	    if (edge[i][2] < edge[i+1][2])
	    {
		memcpy(temp, edge[i], 4 * sizeof(int));
		memcpy(edge[i], edge[i+1], 4 * sizeof(int));
		memcpy(edge[i+1], temp, 4 * sizeof(int));
	    }
	}
    }
}

void GetResult(int origin_flow)
{
    int i;
    int temp_flow = origin_flow, temp;

    result_num = 0;

    for (i=1; i<=M; i++)
    {
	if (edge[i][2] <= temp_flow)
	{
	    memcpy(capacity_cp, capacity, 33 * 33 * sizeof(int));
	    capacity_cp[edge[i][0]][edge[i][1]] -= edge[i][2];
	    temp = MaxFlow(1, N);
	    if (origin_flow - temp == edge[i][2])
	    {
		temp_flow -= edge[i][2];
		result[result_num++] = edge[i][3];
		if (temp_flow == 0)
		{
		    break;
		}
	    }
	}
    }
}

void SortResult(void)
{
    int temp;
    int i, j;

    for (j=result_num-1; j>0; j--)
    {
	for (i=0; i<j; i++)
	{
	    if (result[i] > result[i+1])
	    {
		temp = result[i];
		result[i] = result[i+1];
		result[i+1] = temp;
	    }
	}
    }
}

void PrintResult(FILE *fout, int origin_flow)
{
    int i;
    fprintf(fout, "%d %d\n", origin_flow, result_num);
    for (i=0; i<result_num; i++)
    {
	fprintf(fout, "%d\n", result[i]);
    }
}

int main(void)
{ 
    FILE *fin, *fout;
    int origin_flow;

    fin = fopen("milk6.in", "r"); 
    fout = fopen("milk6.out", "w"); 

    GetInput(fin);
    memcpy(capacity_cp, capacity, 33 * 33 * sizeof(int));
    origin_flow = MaxFlow(1, N);

    SortEdge();
    GetResult(origin_flow);
    SortResult();
    PrintResult(fout, origin_flow);

    return 0;
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值