HDU 2426 Interesting Housing Problem【最大费用最大流 && 常规题】

44 篇文章 0 订阅

Interesting Housing Problem

Time Limit: 10000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2775    Accepted Submission(s): 998


Problem Description
For any school, it is hard to find a feasible accommodation plan with every student assigned to a suitable apartment while keeping everyone happy, let alone an optimal one. Recently the president of University ABC, Peterson, is facing a similar problem. While Peterson does not like the idea of delegating the task directly to the class advisors as so many other schools are doing, he still wants to design a creative plan such that no student is assigned to a room he/she dislikes, and the overall quality of the plan should be maximized. Nevertheless, Peterson does not know how this task could be accomplished, so he asks you to solve this so-called "interesting" problem for him.
Suppose that there are N students and M rooms. Each student is asked to rate some rooms (not necessarily all M rooms) by stating how he/she likes the room. The rating can be represented as an integer, positive value meaning that the student consider the room to be of good quality, zero indicating neutral, or negative implying that the student does not like living in the room. Note that you can never assign a student to a room which he/she has not rated, as the absence of rating indicates that the student cannot live in the room for other reasons.
With limited information available, you've decided to simply find an assignment such that every student is assigned to a room he/she has rated, no two students are assigned to the same room, and the sum of rating is maximized while satisfying Peterson's requirement. The question is … what exactly is the answer?
 

Input
There are multiple test cases in the input file. Each test case begins with three integers, N, M, and E (1 <= N <= 500, 0 <= M <= 500, 0 <= E <= min(N * M, 50000)), followed by E lines, each line containing three numbers, S i, R i, V i, (0 <= S i < N, 0 <= R i < M, |V i| <= 10000), describing the rating V i given by student S i for room R i. It is guaranteed that each student will rate each room at most once.
Each case is followed by one blank line. Input ends with End-of-File.
 

Output
For each test case, please output one integer, the requested value, on a single line, or -1 if no solution could be found. Use the format as indicated in the sample output.
 

Sample Input
  
  
3 5 5 0 1 5 0 2 7 1 1 6 1 2 3 2 4 5 1 1 1 0 0 0 1 1 0
 

Sample Output
  
  
Case 1: 18 Case 2: 0 Case 3: -1

题意:

有N个学生(编号0到N-1)和M个房间(编号0到M-1)。给你E条如(a, b, c)的关系表示学生a对房间b评价为c,当c<0时表示a学生不喜欢b房间,当c为0时表示学生对房间b保持中立态度,当c大于0时表示a学生喜欢房间b。
现在问你存不存在一种方案 保证任意一个学生都不能选上他不喜欢的房间,若存在则输出满足条件的最大评价值之和,若不存在输出-1。


解析:费用法流的常规题,思路很好想,1A么么哒。简单说一下见图步骤:

(1)超级源点到每个学生建边, 容量为1, 费用为0。

(2)每个房间到超级汇点建边,容量为1, 费用为0。

(3)学生到喜欢的房间建边,容量为1, 费用为学生对房间的评价。


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define maxn 2020
#define maxm 220000
#define INF 0x3f3f3f3f

using namespace std;
int n, m, d;
int outset, inset;
struct node {
	int u, v, cap, flow, cost, next;
};

node edge[maxm];
int head[maxn], cnt;
int dist[maxn], vis[maxn];
int per[maxn];

void init(){
	cnt = 0;
	memset(head, -1, sizeof(head));
}

void add(int u, int v, int w, int c){
	node E1 = {u, v, w, 0, c, head[u]};
	edge[cnt] = E1;
	head[u] = cnt++;
	node E2 = {v, u, 0, 0, -c, head[v]};
	edge[cnt] = E2;
	head[v] = cnt++;
}

void getmap(){
	int a, b, c;
	outset = 0;
	inset = n + m + 1;
	for(int i = 1; i <= n; ++i)
		add(outset, i, 1, 0);
	for(int i = 1; i <= m; ++i)
		add(i + n, inset, 1, 0);
	for(int i = 1; i <= d; ++i){
		scanf("%d%d%d", &a, &b, &c);
		a++, b++;
		if(c >= 0)
			add(a, b + n, 1, c);
	}
}

bool SPFA(int st, int ed){
	queue<int>q;
	memset(dist, -INF, sizeof(dist));
	memset(vis, 0, sizeof(vis));
	memset(per, -1, sizeof(per));
	dist[st] = 0;
	vis[st] = 1;
	q.push(st);
	while(!q.empty()){
		int u = q.front();
		q.pop();
		vis[u] = 0;
		for(int i = head[u]; i != -1 ; i = edge[i].next){
			node E = edge[i];
			if(dist[E.v] < dist[u] + E.cost && E.cap > E.flow){
				dist[E.v] = dist[u] + E.cost;
				per[E.v] = i;
				if(!vis[E.v]){
					vis[E.v] = 1;
					q.push(E.v);
				}
			}
		}
	}
	return per[ed] != -1;
}

void MCMF(int st, int ed, int &cost, int &flow){  
    flow = 0;  
    cost = 0;  
    while(SPFA(st, ed)){  
        int mins = INF;  
        for(int i = per[ed]; i != -1; i = per[edge[i ^ 1].v]){  
            mins = min(mins, edge[i].cap - edge[i].flow);  
        }  
        for(int i = per[ed]; i != -1; i = per[edge[i ^ 1].v]){  
            edge[i].flow += mins;  
            edge[i ^ 1].flow -= mins;  
            cost += edge[i].cost * mins;  
        }  
        flow += mins;  
    }  
} 


int main (){
	int k = 0;
	while(scanf("%d%d%d", &n, &m, &d) != EOF){
		init();
		getmap();
		int cost, flow;
		MCMF(outset, inset, cost, flow);
		printf("Case %d: ", ++k);
		if(flow == n)
			printf("%d\n", cost);
		else 
			printf("-1\n");
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值