hdu 2426(KM)

KM简单题,但是要注意一些东西。

1. 题目说的500*500个点的图, 按照KM的复杂度是不能过的, 但是因为这题数据不行, 所以这样也是无压力的可以过, 但是为了保险,还是用邻接表比较好

2. 题目中有一个关键的话 “he still wants to design a creative plan such that no student is assigned to a room he/she dislikes” , 意思就是不能将学生分配到他评价为负的房间,这样就代表了读数据时负边无效。

3.因为没有给出n,m的大小, 所以按照一般的KM算法可能会出现死循环, 这时要加一个判断条件, 当在进行一次匈牙利找增广路未成功时, 如果发现最小的(ui+uj-wij)(x在路径中,而y不在路径中的所有边的最小值)为INF时,就说明算法在往后进行都无法找到增广路,直接返回-1

 

Interesting Housing Problem

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


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 ifor 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
 

 

Source
 

 

Recommend
lcy
 

 

#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <iostream>
using namespace std;
#define N 501
#define INF 0x3fffffff

struct node
{
    int to,next;
    int w;
}edge[50001];

int cnt,pre[N];
int n,m,e;
int frt[N];
int wx[N],wy[N];
int save[N];
int markx[N],marky[N];


void add_edge(int u,int v,int w)
{
    edge[cnt].to=v;
    edge[cnt].w=w;
    edge[cnt].next=pre[u];
    pre[u] = cnt++;
}

int dfs(int s)
{
    markx[s]=1;
    for(int p=pre[s];p!=-1;p=edge[p].next)
    {
        int v=edge[p].to;
        if( wx[s]+wy[v]-edge[p].w < save[v]) save[v]=wx[s]+wy[v]-edge[p].w;
        if(marky[v]==1||wx[s]+wy[v]!=edge[p].w) continue;
        marky[v]=1;
        if(frt[v]==-1 || dfs(frt[v])==1)
        {
            frt[v]=s;
            return 1;
        }
    }
    return 0;
}

int KM()
{
    memset(frt,-1,sizeof(frt));
    memset(wx,0,sizeof(wx));
    memset(wy,0,sizeof(wy));
    for(int i=1;i<=n;i++)
        for(int p=pre[i];p!=-1;p=edge[p].next)
            wx[i]=max(wx[i],edge[p].w);
    for(int i=1;i<=n;i++)
    {
        while(1)
        {
            memset(markx,0,sizeof(markx));
            memset(marky,0,sizeof(marky));
            for(int j=1;j<=m;j++)
                save[j]=INF;
            if( dfs(i) == 1 ) break;
            int mi=INF;
            for(int j=1;j<=m;j++)
                if(marky[j]==0 && save[j]<mi) mi = save[j];
            if(mi==INF) return -1;
            for(int j=1;j<=n;j++)
                if(markx[j]==1) wx[j]-=mi;
            for(int j=1;j<=m;j++)
                if(marky[j]==1) wy[j]+=mi;
        }
    }
    int sum=0;
    for(int i=1;i<=n;i++)
        for(int p=pre[i];p!=-1;p=edge[p].next)
            if(frt[edge[p].to]==i) sum+=edge[p].w;
    return sum;
}

int main()
{
    int tt=1;
    while(scanf("%d%d%d",&n,&m,&e)!=EOF)
    {
        cnt=0;
        memset(pre,-1,sizeof(pre));
        for(int i=0;i<e;i++)
        {
            int x,y;
            int key;
            scanf("%d%d%d",&x,&y,&key);
            x++; y++;
            if(key>=0)
            {
                add_edge(x,y,key);
            }
        }
        printf("Case %d: ",tt++);
        if(n>m) printf("-1\n");
        else
            printf("%d\n",KM());
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值