码迷,mamicode.com
首页 > 其他好文 > 详细

hdu2255-KM(模板)

时间:2020-07-27 09:27:42      阅读:64      评论:0      收藏:0      [点我收藏+]

标签:输入   最小   set   nbsp   details   scanf   pac   str   退出   

 

步骤:

1.首先要找到所有居民愿意花钱最多的 那个房子。
题目中用到lx,ly数组,是为了同时调节两个数组,使得权值和最大。
或者说当要松弛的时候使得 本来最大的矛盾权值和 尽可能的损失小一些来得到 满足条件的最大权值和!
2.(lx[x]+ly[y]-w[x][y]=0)条件下进行匈牙利算法。
#include <iostream>
#include<cstdio>
#include<cstring>

using namespace std;

#define MAX 310
#define INF 1<<25
#define clr(x) memset(x,0,sizeof(x))

/**注:发生矛盾,即几个居民同抢一个房子**/

int w[MAX][MAX];
int n;
int lx[MAX],ly[MAX];
int link[MAX];
int slack[MAX];
int visx[MAX],visy[MAX];

bool dfs(int x)
{
    visx[x]=1; /****得到发生矛盾的居民集合****/

    for(int y=1;y<=n;y++) /**这个居民,每个房子都去试一试!(找到就退出)**/
    {

        if(visy[y])  /****一个房子不需要重复访问****/
            continue;

        int t=lx[x]+ly[y]-w[x][y];/****按这个标准去用-匈牙利算法***/

        if(t==0)/**t==0标志这个房子可以给这位居民**/
        {
            visy[y]=1;

            if(link[y]==0||dfs(link[y])) /****这房子没人住 或 可以让住这个房子的人去找另外的房子住****/

            {
                link[y]=x; return true;/**那么就可以让这位居民住进来**/
            }
        }
        else if(slack[y]>t)/**否则这个房子不能给这位居民!**/

            slack[y]=t;/***就要找到这个房子要松弛多少才能够给这位居民***/

            /***且当有多个居民都对这个房子有松弛量时,要找到最小的。****/
    }
    return false;
}

int KM()
{
    clr(lx);

    clr(ly);

    clr(link);

    /*****首先把每个居民出的钱最多的那个房子赋给它******/

    for(int i=1;i<=n;i++) 
        for(int j=1;j<=n;j++)
            if(lx[i]<w[i][j])
                lx[i]=w[i][j];

                /*****n循环-在满足了以前居民的情况下-给第i个居民安置房子*****/

    for(int i=1;i<=n;i++)
    {

        for(int j=1;j<=n;j++) slack[j]=INF; /***松弛量***//****这个松弛量不需要每次dfs都初始化一次;因为它跟visy有关***/

        while(1)/****死循环-在于一定要给这个居民找到房子为止!****/
        {

            clr(visx);

            clr(visy);

            if(dfs(i))  /***找到房子就跳出死循环***/

            break;

            int d=INF;

            for(int k=1;k<=n;k++)

                if(!visy[k]&&d>slack[k])

                    d=slack[k];        /****找到最小松弛量*****/

            for(int k=1;k<=n;k++)/****松弛操作-使发生矛盾的居民有更多选择*****/

            {

                if(visx[k])        /*****将矛盾居民的要求降低,使他们有更多可房子选择*****/

                     lx[k]-=d;

                if(visy[k])       /****使发生矛盾的房子在下一个子图,保持矛盾(即保持原子图性质)*****/

                    ly[k]+=d;

            }

        }

    }

    int ans=0;

    for(int i=1;i<=n;i++)

        ans+=w[link[i]][i];

    return ans;

 

}

int main()
{
    while(~scanf("%d",&n))
    {
        clr(w);//每个案列都要重新置0;

        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)

                scanf("%d",&w[i][j]);//输入每边权值

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

    }

    return 0;
}
可以参考
https://blog.csdn.net/wuxinxiaohuangdou/article/details/14056987

hdu2255-KM(模板)

标签:输入   最小   set   nbsp   details   scanf   pac   str   退出   

原文地址:https://www.cnblogs.com/lijiahui-123/p/13383015.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!