Drainage Ditches

题意:求有向图的最大流

解题思路

  1. 参考USACO这篇阅读文献的伪代码(http://cerberus.delos.com:791/usacotext2?a=59NtETPig5G&S=flow)即可
  2. 要注意的是两点之间可能有多条边,将这些边的流量加起来,看作一条边即可

代码

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

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

#define MAX_N 200
#define MAX_M 200

int N, M, ceiling = 1;
int capacity[MAX_M + 1][MAX_M + 1];

int GetMin(int a, int b)
{
    return a < b ? a : b;
}

int GetFlow(int source, int sink)
{
    int prevnode[MAX_M + 1];
    int flow[MAX_M + 1];
    int visited[MAX_M + 1];
    int total_flow = 0;
    int i, max_flow, max_loc, curnode, nextnode;

    if (source == sink)
    {
	return ceiling;
    }

    while (1)
    {
	for (i=1; i<=M; i++)
	{
	    prevnode[i] = -1;
	    flow[i] = 0;
	    visited[i] = 0;
	}
	flow[source] = ceiling;

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

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

	    for (i=1; i<=M; i++)
	    {
		if (capacity[max_loc][i] != 0)
		{
		    if (flow[i] < GetMin(max_flow, capacity[max_loc][i]))
		    {
			prevnode[i] = max_loc;
			flow[i] = GetMin(max_flow, capacity[max_loc][i]);
		    }
		}
	    }
	}

	if (max_loc == -1)
	{
	    break;
	}
	total_flow += flow[sink];

	curnode = sink;
	
	while (curnode != source)
	{
	    nextnode = prevnode[curnode];
	    capacity[nextnode][curnode] -= flow[sink];
	    capacity[curnode][nextnode] += flow[sink];
	    curnode = nextnode;
	}
    }

    return total_flow;
}

int main(void)
{
    FILE *fin, *fout;
    int p1, p2, cap, i;

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

    memset(capacity, 0, (MAX_M + 1) * (MAX_M + 1) * sizeof(int));
    fscanf(fin, "%d %d", &N, &M);
    for (i=0; i<N; i++)
    {
	fscanf(fin, "%d %d %d", &p1, &p2, &cap);
	capacity[p1][p2] += cap;
	if (p2 == M)
	{
	ceiling += cap;
	}
    }

    fprintf(fout, "%d\n", GetFlow(1, M));

    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值