HDU 2426 Interesting Housing Problem(EK模板)

来源:互联网 发布:个人域名申请 编辑:程序博客网 时间:2024/05/22 12:22

题目地址
题意:有n个学生和m个宿舍,每个宿舍只能一个人住,然后接下来的E行有a,b,c三个数,代表的是学生a对宿舍b的满意度为c,假如满意度小于0则不会入住该宿舍,如果没有写出满意度则代表的是不会入住该宿舍。求所有学生能不能入住成功,最大的满意度为多少?
思路:如果最后满意的宿舍比n小则说明了不可能成功入住,所有直接输出-1,否则进行带权二分图最佳匹配EK算法就好了,模板题

#include <iostream>#include <cstring>#include <string>#include <queue>#include <vector>#include <map>#include <set>#include <stack>#include <cmath>#include <cstdio>#include <algorithm>#include <iomanip>#define N 1000#define M 500010#define LL __int64#define inf 0x3f3f3f3f#define lson l,mid,ans<<1#define rson mid+1,r,ans<<1|1#define getMid (l+r)>>1#define movel ans<<1#define mover ans<<1|1using namespace std;const LL mod = 1e9 + 7;int mapp[N][N];//表明好感度bool usem[N];struct Kuhn_Munkras {    int nx, ny;    int linker[N];//每个y所对应的x    int lx[N];//x的期望值    int ly[N];//y的期望值    int slack[N];//每个y能被x匹配的最小还需的期望值    bool visx[N], visy[N];//匹配过的标记    void init(int n, int m) {        this->nx = n;        this->ny = m;        memset(linker, -1, sizeof(linker));//每个y最初都没有匹配        memset(ly, 0, sizeof(ly));//最初每个y的期望值都是0    }    bool dfs(int x) {        visx[x] = true;        for (int y = 1; y <= ny; y++) {            if (!visy[y]) {                int tmp = lx[x] + ly[y] - mapp[x][y];                if (tmp == 0) {//如果两边的期望值相加等于好感度则符合要求                    visy[y] = true;                    if (linker[y] == -1 || dfs(linker[y])) {//没有被匹配过的y,或者能换匹配的y                        linker[y] = x;                        return true;                    }                }                else if (slack[y]>tmp) {                    slack[y] = tmp; //可以理解为该y要得到x的匹配,还需多少期望值,取最小值                }            }        }        return false;    }    int solve(int n, int m) {        init(n, m);        for (int i = 1; i <= nx; i++) {            lx[i] = -inf;            for (int j = 1; j <= ny; j++) {                if (mapp[i][j]>lx[i]) {                    lx[i] = mapp[i][j];//取最大的好感度为x的期望值                }            }        }        for (int x = 1; x <= nx; x++) {//尝试为每一个x解决匹配问题            memset(slack, inf, sizeof(slack));            while (true) {//找不到就降低期望值                memset(visx, false, sizeof(visx));                memset(visy, false, sizeof(visy));                if (dfs(x)) {//找到就离开                    break;                }                int d = inf;                for (int i = 1; i <= ny; i++) {                    if (!visy[i] && d>slack[i]) {//找到最小的差值                        d = slack[i];                    }                }                for (int i = 1; i <= nx; i++) {//对所有访问过的x减小期望值                    if (visx[i]) {                        lx[i] -= d;                    }                }                for (int i = 1; i <= ny; i++) {//对所有访问过的y增加期望值                    if (visy[i]) {                        ly[i] += d;                    }                    else {                        slack[i] -= d;                    }                }            }        }        int res = 0;        for (int i = 1; i <= ny; i++) {            if (linker[i] != -1) {//匹配成功的求和                res += mapp[linker[i]][i];            }        }        return res;    }}KM;int main() {    int n, m, E;    int a, b, c;    int Case = 1;    cin.sync_with_stdio(false);    while (cin >> n >> m >> E) {        memset(mapp, -inf, sizeof(mapp));        memset(usem, false, sizeof(usem));        for (int i = 0; i < E; i++) {            cin >> a >> b >> c;            a++, b++;            if (c >= 0) mapp[a][b] = c, usem[b] = true;        }        a = 0;        for (int i = 1; i <= m; i++) {            if (usem[i]) a++;        }        if (a < n) {            cout << "Case " << Case++ << ": -1" << endl;            continue;        }        cout << "Case " << Case++ << ": " << KM.solve(n, m) << endl;    }    return 0;}
阅读全文
0 0