HDU 2255 Benefiting from a well-off society and making a fortune (KM algorithm)

Topic link: http://acm.hdu.edu.cn/showproblem.php?pid=2255

Problem Description
Legend has it that there was a very wealthy village in a faraway place, and one day, the head of the village decided to reform the system: redistribute houses.
This is a major event, and it is related to the housing issue of the people. There are a total of n rooms in the village, and there are just n families of people. Considering that each family must have a house (if there are people who do not have a house to live in, it is easy to cause instability), each family must be allocated a house and can only get one house. house.
On the other hand, the village head and other village leaders want to get the maximum benefit, so that the institutions in the village will have money. Since the common people are relatively wealthy, they can pay a certain price for each house within their economic range. , For example, if there are 3 houses, an ordinary family can pay 100,000 yuan for the first house, 20,000 yuan for the second house, and 200,000 yuan for the third house (of course within their economic scope). Now the problem is the village How can the leaders allocate houses to maximize their income. (Even if the villagers have the money to buy a house, they may not be able to buy it, it depends on the allocation of the village leaders).
 

Input
The input data contains multiple sets of test cases. The first line of each set of data is input n, which represents the number of houses (also the number of ordinary people's homes), followed by n lines, and the n numbers in each line represent the ith village name versus the jth The price of the room (n<=300).
 

Output
Please output the maximum income value for each group of data, and the output of each group occupies one line.

 

Sample Input
 
  
2
100 10
15 23
 

Sample Output
 
  
123

Topic idea: maximum matching of weighted bipartite graph, KM algorithm bare question

Code:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<map>

using namespace std;

#define FOU(i,x,y) for(int i=x;i<=y;i++)
#define FOD(i,x,y) for(int i=x;i>=y;i--)
#define MEM(a,val) memset(a,val,sizeof(a))
#define PI acos(-1.0)

const double EXP = 1e-9;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
const ll MINF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;


const int N = 310;
int nx,ny; //points on both sides
int g[N][N]; //Bipartite graph description, g[i][j] represents the weight between i and j, the maximum matching is initialized to -INF to indicate infinite, and the minimum matching is similarly initialized to INF
int linker[N]; //record which x of the y link, -1 means none
int lx[N],ly[N];//The matching status of each point in y, the point label in x, y
int slack[N]; //slack is the modifier
bool visx[N],visy[N];

bool DFS(int x)
{
    visx[x] = true;
    for(int y = 0; y < ny; y++)
    {
        if(visy[y])continue; //Continue after use
        int tmp = lx[x] + ly[y] - g[x][y];
        if(tmp == 0) // meet the matching requirements
        {
            visy[y] = true;
            if(linker[y] == -1 || DFS(linker[y]))
            {
                linker[y] = x;
                return true;
            }
        }
        else if(slack[y] > tmp)
            slack[y] = tmp;
    }
    return false;
}
int KM ()
{
    memset(linker,-1,sizeof(linker));
    memset(ly,0,sizeof(ly)); //The expected value of the initial right side is all 0
    for(int i = 0;i < nx;i++)
    {
        lx[i] = -INF; //The expected value on the left is the maximum edge weight
        for(int j = 0;j < ny;j++)
            if(g[i][j] > lx[i])
                lx[i] = g[i][j];
    }

    //Start to solve the left matching problem
    for(int x = 0;x < nx;x++)
    {
        for(int i = 0;i < ny;i++)
            slack[i] = INF; //Because the minimum value is taken, it is initialized to infinity
        while(true)
        {
            // The way to solve the home problem for the left is: if you can't find it, lower the expectation until you find it

            // Record whether the left and right sides have been tried to match in each round of matching
            memset(visx,false,sizeof(visx));
            memset(visy,false,sizeof(visy));
            if(DFS(x)) //find a match, exit
                break;
            //Not found, lower expectations
            //minimum can reduce the expected value
            int d = INF;
            for(int i = 0;i < ny;i++)
                if(!visy[i] && d > slack[i])
                    d = slack[i];
            for(int i = 0;i < nx;i++)
                if(visx[i])
                    lx[i] -= d;
            for(int i = 0;i < ny;i++)
            {
                if(visy[i])ly[i] += d;
                else slack[i] -= d;
            }
        }
    }
    int res = 0;
    for(int i = 0;i < ny;i++)
        if(linker[i] != -1)
            res += g[linker[i]][i];
    return res;
}

intmain()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    std::ios::sync_with_stdio(false);
    int n;
    while(~scanf("%d",&n))
    {
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                scanf("%d",&g[i][j]);
        nx = ny = n;
        printf("%d\n",KM());
    }
    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324857477&siteId=291194637