Ural-1076 Trash(最小费用最大流算法)

Trash
Time Limit:1000MS     Memory Limit:16384KB  
Description
You were just hired as CEO of the local junkyard.One of your jobs is dealing with the incoming trash and sorting it for recycling.The trash comes every day in N containers and each of these containers contains certain amount of each of the N types of trash. Given the amount of trash in the containers find the optimal way to sort the trash. Sorting the trash means putting every type of trash in separate container. Each of the given containers has infinite capacity. The effort for moving one unit of trash from container i to j is 1 if i ≠ j otherwise it is 0.You are to minimize the total effort.
Input
The first line contains the number N (1 ≤ N ≤ 150), the rest of the input contains the descriptions of the containers.The (1 + i)-th line contains the description of the i-th container the j-th amount (0 ≤ amount ≤ 100) on this line denotes the amount of the j-th type of trash in the i-th container.
Output
You should write the minimal effort that is required for sorting the trash.
Sample Input
input
4
62 41 86 94
73 58 11 12
69 93 89 88

81 40 69 13

output

650

最小费用最大流模板:http://blog.csdn.net/u014492306/article/details/38491169

题意:给n辆卡车n种垃圾,每辆卡车都有各种垃圾若干,从一辆车转移1单位垃圾到另一辆车需1花费,求使各车只有一种垃圾所需的最小花费。

   采用最小费用最大流算法,建立网络流图:

对每个卡车i,建立容量为1,费用为0的有向边(st,i)和一条容量为0,费用为0的有向边(i,st);

对每类垃圾i,建立一条容量为1,费用为0的有向边(i,en)和一条容量为0,费用为0的有向边(en,i);

对集装箱i和垃圾j,建立一条容量为1,费用为s[i]-r[i][j](即该卡车除垃圾j以外的垃圾处理费用)的有向边(i,j)和容量为0,费用为-(s[i]-r[i][j])的有向边(j,i);

建完网络流图变可直接用网络流模板计算费用ans。

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
#define Max 310
#define inf 0x3f3f3f3f
int n, ans,en,st;
int cap[Max][Max], pre[Max];
int cost[Max][Max], dis[Max];
int que[Max];
bool vis[Max];
int r[Max][Max],s[Max];
bool spfa(){                  //  源点为0,汇点为n。
    int i, head = 0, tail = 1;
    for(i = 1; i <= n; i ++){
        dis[i] = inf;
        vis[i] = false;
    }
    dis[st] = 0;
    que[0] = st;
    vis[st] = true;
    while(tail != head){      //  循环队列。
        int u = que[head];
        for(i = 1; i <= n; i ++)
            if(cap[u][i] && dis[i] > dis[u] + cost[u][i]){    //  存在路径,且权值变小。
                dis[i] = dis[u] + cost[u][i];
                pre[i] = u;
                if(!vis[i]){
                    vis[i] = true;
                    que[tail ++] = i;
                    if(tail == Max) tail = 0;
                }
            }
        vis[u] = false;
        head ++;
        if(head == Max) head = 0;
    }
    if(dis[en] == inf) return false;
    return true;
}
 
void end(){
    int i, sum = inf;
    for(i = en; i != st; i = pre[i])
        sum =sum<cap[pre[i]][i]?sum:cap[pre[i]][i];
    for(i = en; i != st; i = pre[i]){
        cap[pre[i]][i] -= sum;
        cap[i][pre[i]] += sum;
        ans += cost[pre[i]][i] * sum;   //  cost[][]记录的为单位流量费用,必须得乘以流量。
    }
}
 
int main(){
	int i,j;
	scanf("%d",&n);
	memset(cap,0,sizeof(cap));
	memset(s,0,sizeof(s));
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++)
		{
			scanf("%d",&r[i][j+n]);
			s[i]+=r[i][j+n];
		}
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++)
		{
			//scanf("%d",&cost[i][j+n]);
			cost[i][j+n]=s[i]-r[i][j+n];
			cap[i][j+n]=1;
			cap[j+n][i]=0;
			cost[j+n][i]=-cost[i][j+n];
		}
		st=2*n+1;
		en=2*n+2;
		for(i=1;i<=n;i++)
		{
			cap[st][i]=1;
			cap[i][st]=0;
			cost[st][i]=cost[i][st]=0;
			cap[i+n][en]=1;
			cap[en][i+n]=0;
			cost[en][i+n]=cost[i+n][en]=0;
		}
    ans = 0;
	n=2*n+2;
    while(spfa()) end();
    printf("%d\n",ans);
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值