P - 奔小康赚大钱 - hdu 2255(带权值的匹配)

分析:这是一个KM的模板题,也就不多说了,KM最复杂的情况都能过,下面是没有优化过的代码:

************************************************************

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

const int MAXN = 305;
const int oo = 1e9+7;

int w[MAXN][MAXN], N;
int dx[MAXN], dy[MAXN];
int Ly[MAXN], slack[MAXN];
bool vx[MAXN], vy[MAXN];

bool Find(int i)
{///别忘记vx[i]赋值true,表示可以增广的时候达到了i点
    vx[i] = true;
    for(int j=1; j<=N; j++)
    {
        if( !vy[j] && dx[i]+dy[j] == w[i][j] )
        {
            vy[j] = true;

if( !Ly[j] || Find(Ly[j]) )
            {
                Ly[j] = i;
                return true;
            }
        }
        ///else if(vy[j] == false)
           /// slack[j] = min(slack[j], dx[i]+dy[j]-w[i][j]);
    }

return false;
}
int KM()
{
    int i, j, k;

for(i=1; i<=N; i++) while(1)
    {///给每个点进行增广,找不到减去一个d,继续找

memset(vx, false, sizeof(vx));
        memset(vy, false, sizeof(vy));

if( Find(i) == true) break;

int d = oo;

for(j=1; j<=N; j++) if( vx[j] )
        for(k=1; k<=N; k++) if( !vy[k] )
        {///用访问过的左边和未访问过的右边求出来一个最小的d
            d = min( d,  dx[j]+dy[k]-w[j][k]);
        }

for(j=1; j<=N; j++)
        {///左边的标杆减去d,右边的加上d,这样原来匹配的值没有改变
         ///减去d的目的是为了查找那个可以增广的边里面最大的那个
            if(vx[j])dx[j] -= d;
            if(vy[j])dy[j] += d;
        }
    }

int sum = 0;

for(i=1; i<=N; i++)
    {
        sum += w[ Ly[i] ][i];
    }

return sum;
}

int main()
{
    while(scanf("%d", &N) != EOF)
    {
        memset(dx, false, sizeof(dx));
        memset(dy, false, sizeof(dy));
        memset(Ly, false, sizeof(Ly));

for(int i=1; i<=N; i++)
        for(int j=1; j<=N; j++)
        {
            scanf("%d", &w[i][j]);
            dx[i] = max(dx[i], w[i][j]);
        }

printf("%d\n", KM());
    }

return 0;
}

*********************************************************************

下面是优化过的,感觉时间上减少的不是那么明显,少了100多ms

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

const int MAXN = 305;
const int oo = 1e9+7;

int w[MAXN][MAXN], N;
int dx[MAXN], dy[MAXN];
int Ly[MAXN], slack[MAXN];
bool vx[MAXN], vy[MAXN];

bool Find(int i)
{///别忘记vx[i]赋值true,表示可以增广的时候达到了i点
    vx[i] = true;
    for(int j=1; j<=N; j++)
    {
        if( !vy[j] && dx[i]+dy[j] == w[i][j] )
        {
            vy[j] = true;

if( !Ly[j] || Find(Ly[j]) )
            {
                Ly[j] = i;
                return true;
            }
        }
        else if(vy[j] == false)
            slack[j] = min(slack[j], dx[i]+dy[j]-w[i][j]);
    }

return false;
}
int KM()
{
    int i, j;

for(i=1; i<=N; i++)
    {
        for(j=1; j<=N; j++)
            slack[j] = oo;

while(true)
        {
            memset(vx, false, sizeof(vx));
            memset(vy, false, sizeof(vy));

if( Find(i) == true )break;

int d = oo;

for(j=1; j<=N; j++)
            {
                if(!vy[j] && d > slack[j])
                    d = slack[j];
            }

for(j=1; j<=N; j++)
            {
                if(vx[j])dx[j] -= d;
                if(vy[j])dy[j] += d;
                else slack[j] -= d;
            }
        }
    }

int sum = 0;

for(i=1; i<=N; i++)
    {
        sum += w[ Ly[i] ][i];
    }

return sum;
}

int main()
{
    while(scanf("%d", &N) != EOF)
    {
        memset(dx, false, sizeof(dx));
        memset(dy, false, sizeof(dy));
        memset(Ly, false, sizeof(Ly));

for(int i=1; i<=N; i++)
        for(int j=1; j<=N; j++)
        {
            scanf("%d", &w[i][j]);
            dx[i] = max(dx[i], w[i][j]);
        }

printf("%d\n", KM());
    }

return 0;
}

时间: 2024-10-22 14:18:16

P - 奔小康赚大钱 - hdu 2255(带权值的匹配)的相关文章

奔小康赚大钱 hdu 2255

奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4211    Accepted Submission(s): 1825 Problem Description 传说在遥远的地方有一个很富裕的村落,有一天,村长决定进行制度改革:又一次分配房子. 这但是一件大事,关系到人民的住房问题啊.村里共同拥有n间房间,刚好有n家老百姓

P - 奔小康赚大钱HDU 2255

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;const int maxn = 310;const int INF = 0x3f3f3f3f;int maps[maxn][maxn], lx[maxn], ly[maxn];int visx[maxn], visy[maxn], s[maxn], used[maxn],

hdu 2255 奔小康赚大钱(KM算法)

奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3248    Accepted Submission(s): 1413 Problem Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓,考

HDU 2255 ——奔小康赚大钱——————【KM算法裸题】

奔小康赚大钱 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 2255 Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子住的话,容易引起不安定因素),每家必须分配到

[ACM] HDU 2255 奔小康赚大钱 (二分图最大权匹配,KM算法)

奔小康赚大钱 Problem Description 传说在遥远的地方有一个很富裕的村落,有一天,村长决定进行制度改革:又一次分配房子. 这但是一件大事,关系到人民的住房问题啊. 村里共同拥有n间房间,刚好有n家老百姓,考虑到每家都要有房住(假设有老百姓没房子住的话.easy引起不安定因素),每家必须分配到一间房子且仅仅能得到一间房子. 还有一方面,村长和另外的村领导希望得到最大的效益,这样村里的机构才会有钱.因为老百姓都比較富裕,他们都能对每一间房子在他们的经济范围内出一定的价格,比方有3间房

HDU 2255 奔小康赚大钱 (KM算法 模板)

A - 奔小康赚大钱 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子住的话,容易引起不安定因素),每家必须分配到一间房子且只能得到一间房子.

最大流增广路(KM算法) HDOJ 2255 奔小康赚大钱

题目传送门 1 /* 2 KM:裸题第一道,好像就是hungary的升级版,不好理解,写点注释 3 KM算法用来解决最大权匹配问题: 在一个二分图内,左顶点为X,右顶点为Y,现对于每组左右连接Xi,Yj有权w(i,j), 4 求一种匹配使得所有w(i,j)的和最大.也就是最大权匹配一定是完备匹配.如果两边的点数相等则是完美匹配. 5 如果点数不相等,其实可以虚拟一些点,使得点数相等,也成为了完美匹配.最大权匹配还可以用最大流去解决 6 */ 7 #include <cstdio> 8 #inc

hdu2255 奔小康赚大钱 km算法解决最优匹配(最大权完美匹配)

/** 题目:hdu2255 奔小康赚大钱 km算法 链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255 题意:lv 思路:最优匹配(最大权完美匹配) km算法 模板来自:http://www.cnblogs.com/wenruo/p/5264235.html 如果是求最小权完美匹配,那么将所有权值取相反数,然后求得最大权,输出最大权的相反数即可. */ #include <iostream> #include <cstring> #

奔小康赚大钱(二分图最大权匹配)

奔小康赚大钱 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 2255 Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子住的话,容易引起不安定因素),每家必须分配到