HDU 2426 Interesting Housing Problem 二分匹配(KM模板)或者最小费用最大流

来源:互联网 发布:职称论文比较软件 编辑:程序博客网 时间:2024/05/17 05:00

点击打开链接

Interesting Housing Problem

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


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, Si, Ri, Vi, (0 <= Si < N, 0 <= Ri < M, |Vi| <= 10000), describing the rating Vi given by student Si for room Ri. 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 50 1 50 2 71 1 61 2 32 4 51 1 10 0 01 1 0
 

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

Source
2008 Asia Hangzhou Regional Contest Online
 

Recommend
lcy
 
 
题意:一个学校里面有n个学生,m个宿舍,学生对某一宿舍有一个r值,代表该学生对该宿舍的满意度,r>0说明满意,r=0,说明不喜欢也不讨厌,r<0,说明讨厌。每个宿舍只住一个学生,校长应该怎么分配学生才能使得满意度达到最大?
用二分匹配来做比较简单,直接套KM模板就行。如果最小费用最大流的话,关键在于建图,建一个超级源点与学生相连,超级汇点与宿舍相连,学生和宿舍之间也有联系。但是,我用最小费用最大流来做此题,结果是TLE,可能有些地方没有优化好,不过,我知道,用最小费用最大流的思想是可以AC此题的。
 
//二分匹配#include<stdio.h>#include<string.h>#define inf 99999using namespace std;int g[507][507];int lx[507],ly[507];int slack[507],match[507];bool visx[507],visy[507];int n,m,t;bool dfs(int cur){    visx[cur]=true;    for(int y=1;y<=m;y++)    {        if(visy[y])continue;        int t=lx[cur]+ly[y]-g[cur][y];        if(t==0)        {            visy[y]=true;            if(match[y]==-1||dfs(match[y]))            {                match[y]=cur;                return true;            }        }        else if(slack[y]>t)        {            slack[y]=t;        }    }    return false;}int KM(){    memset(match,-1,sizeof(match));    memset(ly,0,sizeof(ly));    for(int i=1;i<=n;i++)    {        lx[i]=-inf;        for(int j=1;j<=m;j++)        {            if(g[i][j]>lx[i])            lx[i]=g[i][j];        }    }    for(int x=1;x<=n;x++)    {        for(int i=1;i<=m;i++)        slack[i]=inf;        while(true)        {            memset(visx,false,sizeof(visx));            memset(visy,false,sizeof(visy));            if(dfs(x))break;            int d=inf;            for(int i=1;i<=m;i++)            {                if(!visy[i]&&d>slack[i])                d=slack[i];            }            for(int i=1;i<=n;i++)            if(visx[i])            {                lx[i]-=d;            }            for(int i=1;i<=m;i++)            if(visy[i])ly[i]+=d;            else slack[i]-=d;        }    }    int reslut=0,flag=0;    for(int i=1;i<=m;i++)    {        if(match[i]==-1||g[match[i]][i]==-inf)        continue;        if(match[i]>-1)        {            reslut+=g[match[i]][i];            flag++;        }    }    if(flag<n)reslut=-1;    return reslut;}int main(){    int cas=1;    while(scanf("%d%d%d",&n,&m,&t)!=EOF)    {        memset(g,0,sizeof(g));        for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)        g[i][j]=-inf;        int a,b,c;        for(int i=1;i<=t;i++)        {            scanf("%d%d%d",&a,&b,&c);            a++;b++;            if(c<0)continue;            g[a][b]=c;        }        int ans=KM();        printf("Case %d: %d\n",cas++,ans);    }    return 0;}

 
//TLE的最小费用最大流#include <iostream>#include <algorithm>#include <string>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <memory.h>#include <queue>#include <vector>#include <cmath>using namespace std;int sumFlow;const int MAXN = 507;const int INF = 1000000000;struct Edge{    int u, v, cap, cost;    int next;} edge[250000];int NE,N,M,E;int head[MAXN], dist[MAXN], pp[MAXN];bool vis[MAXN];void init(){    NE = 0;    memset(head, -1, sizeof(head));}void addedge(int u, int v, int cap, int cost){    edge[NE].u = u;    edge[NE].v = v;    edge[NE].cap = cap;    edge[NE].cost = cost;    edge[NE].next = head[u];    head[u] = NE++;    edge[NE].u = v;    edge[NE].v = u;    edge[NE].cap = 0;    edge[NE].cost = -cost;    edge[NE].next = head[v];    head[v] = NE++;}bool SPFA(int s, int t, int n){    int i, u, v;    queue <int> qu;    memset(vis,false,sizeof(vis));    memset(pp,-1,sizeof(pp));    for(i = 0; i <= n; i++) dist[i] = INF;    vis[s] = true;    dist[s] = 0;    qu.push(s);    while(!qu.empty())    {        u = qu.front();        qu.pop();        vis[u] = false;        for(i = head[u]; i != -1; i = edge[i].next)        {            v = edge[i].v;            if(edge[i].cap && dist[v] > dist[u] + edge[i].cost)            {                dist[v] = dist[u] + edge[i].cost;                pp[v] = i;                if(!vis[v])                {                    qu.push(v);                    vis[v] = true;                }            }        }    }    if(dist[t] == INF) return false;    return true;}int MCMF(int s, int t, int n) // minCostMaxFlow{    int flow = 0; // 总流量    int i, minflow, mincost;    mincost = 0;    while(SPFA(s, t, n))    {        minflow = INF + 1;        for(i = pp[t]; i != -1; i = pp[edge[i].u])            if(edge[i].cap < minflow)                minflow = edge[i].cap;        flow += minflow;        for(i = pp[t]; i != -1; i = pp[edge[i].u])        {            edge[i].cap -= minflow;            edge[i^1].cap += minflow;        }        mincost += dist[t] * minflow;    }    sumFlow = flow; // 最大流    if(sumFlow!=N) return 1;    return mincost;}int main(){    int cas=1;    while(scanf("%d%d%d",&N,&M,&E)!=EOF)    {        int u, v, c;        int s,r,vv;        init();        int S=0;//S是源点        int T=N+M+1;//T是汇点        for(int i=0;i<E;i++)        {            scanf("%d%d%d",&s,&r,&vv);            s++,r++;            if(v>=0)            {                addedge(s,N+r,1,-vv);            }        }        for(int i=1;i<=N;i++)        {            addedge(0,i,1,0);        }        for(int i=1;i<=M;i++)        addedge(N+i,T,1,0);        int ans =- MCMF(S, T, T+1);//T+1是点的个数        printf("Case %d: %d\n", cas++,ans);    }    return 0;}