HDU 2426 Interesting Housing Problem 最小费用最大流 or KM算法

来源:互联网 发布:淘宝刷运费险 编辑:程序博客网 时间:2024/05/21 10:47

这道题貌似是08年杭州网络赛的题目, 看完题后就发现是个最优匹配问题,用KM或者最小费用最大流做, 就找了个最小费用最大流的模板,改了一下,就能过了、

建图还是比较好想的,建立一个超级源点,一个超级汇点,然后源点与学生连边,流量限制为1,费用为0,汇点与房间连边,流量限制为1, 费用为0, 然后学生与房间之间的边,流量限制是1,费用就是题目给的喜好值了, 注意,每次加边,都要加一个相应的反向边, 就是流量为0, 费用为正向边的负数。

然后题目中要求不能把学生分到不喜欢的房间里,所以碰见喜好值是负数就不管了。 另外,由于是最小费用么,所以所有喜好值都是乘以-1后加进去的,这样求出的最小值,输出的时候再乘以-1就变成最大的了。

最后判断能不能所有学生都分配到房间里, 就判断流量的大小是否等于学生个数就行了


/*ID: sdj22251PROG: subsetLANG: C++*/#include <iostream>#include <vector>#include <list>#include <map>#include <set>#include <deque>#include <queue>#include <stack>#include <bitset>#include <algorithm>#include <functional>#include <numeric>#include <utility>#include <sstream>#include <iomanip>#include <cstdio>#include <cmath>#include <cstdlib>#include <cctype>#include <string>#include <cstring>#include <cmath>#include <ctime>#define MAXN 100005#define eps 1e-11#define L(x) x<<1#define R(x) x<<1|1using namespace std;int tot = 0, x, y;class mincost{private:    const static int V = 2001; //注意点的个数, 应该为学生+房间+2, 所以至少要开到1002    const static int E = 2000001;    const static int INF = -1u >> 1;    struct Edge    {        int v, cap, cost;        Edge *next;    } pool[E], *g[V], *pp, *pree[V];    int T, S, dis[V], pre[V];    int n, m, flow, cirq[V];    void SPFA();    inline void addedge(int i, int j, int cap, int cost);public:    bool initialize(int x, int y, int z);    void mincost_maxflow();};void mincost::mincost_maxflow(){    while (true)    {        SPFA();        if (dis[T] == INF)            break;        int minn = INF;        for (int i = T; i != S; i = pre[i])            minn = min(minn, pree[i]->cap);        for (int i = T; i != S; i = pre[i])        {            pree[i]->cap -= minn;            pool[(pree[i] - pool)^0x1].cap += minn;            flow += minn * pree[i]->cost;                    }        tot += minn;  //流量计算    }    if(tot != x) flow = 1;    printf("%d\n", -flow);}void mincost::SPFA(){    bool vst[V] = {false};    int tail = 0, u;    fill(dis,dis + n,0x7fffffff);    cirq[0] = S;    vst[S] = 1;    dis[S] = 0;    for (int i = 0; i <= tail; i++)    {        int v = cirq[i % n];        for (Edge *i = g[v]; i != NULL; i = i->next)        {            if (!i->cap)                continue;            u = i->v;            if (i->cost + dis[v] < dis[u])            {                dis[u] = i->cost + dis[v];                pree[u] = i;                pre[u] = v;                if (!vst[u])                {                    tail++;                    cirq[tail % n] = u;                    vst[u] = true;                }            }        }        vst[v] = false;    }}void mincost::addedge(int i, int j, int cap, int cost){    pp->cap = cap;    pp->v = j;    pp->cost = cost;    pp->next = g[i];    g[i] = pp++;}bool mincost::initialize(int x, int y, int z){    memset(g, 0, sizeof (g));    pp = pool;    n = x + y + 2;  //n即为顶点的个数   学生数+房间数+一个源点+一个汇点    m = z;    S = 0;    T = x + y + 1;    int v, u, f, c;    for (int i = 0; i < m; i++)    {        scanf("%d %d %d", &v, &u, &c);        v++;        u++;        if(c >= 0)        {            addedge(v, u + x, 1, -c);            addedge(u + x, v, 0, c);        }    }    for(int i = 1; i <= x; i++)    {        addedge(0, i, 1, 0);        addedge(i, 0, 0, 0);    }    for(int i = 1; i <= y; i++)    {        addedge(x + i, T, 1, 0);        addedge(T, x + i, 0, 0);    }    flow = 0;    return true;}mincost g;int main(){    //freopen("d:/data.in","r",stdin);    //freopen("d:/data.out","w",stdout);    int  z, cas = 0;    while(scanf("%d%d%d", &x, &y, &z) != EOF)    {        g.initialize(x, y, z);        printf("Case %d: ", ++cas);        tot = 0;        g.mincost_maxflow();    }    return 0;}

接下来是KM算法的 最后判断是否完备匹配就行了


#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <queue>#define MAXN 505#define MAXM 555555#define INF 1000000000using namespace std;int n, m, ny, nx;int w[MAXN][MAXN];int lx[MAXN], ly[MAXN];int linky[MAXN];int visx[MAXN], visy[MAXN];int slack[MAXN];bool find(int x){    visx[x] = 1;    for(int y = 1; y <= ny; y++)    {        if(visy[y]) continue;        int t = lx[x] + ly[y] - w[x][y];        if(t == 0)        {            visy[y] = 1;            if(linky[y] == -1 || find(linky[y]))            {                linky[y] = x;                return true;            }        }         else if(slack[y] > t) slack[y] = t;    }    return false;}void KM(){    memset(linky, -1, sizeof(linky));    for(int i = 1; i <= nx; i++) lx[i] = -INF;    memset(ly, 0, sizeof(ly));    for(int i = 1; i <= nx; i++)        for(int j = 1; j <= ny; j++)            if(w[i][j] > lx[i]) lx[i] = w[i][j];    for(int x = 1; x <= nx; x++)    {        for(int i = 1; i <= ny; i++) slack[i] = INF;        while(true)        {            memset(visx, 0, sizeof(visx));memset(visy, 0, sizeof(visy));if(find(x)) break;int d = INF;for(int i = 1; i <= ny; i++)                if(!visy[i]) d = min(d, slack[i]);            for(int i = 1; i <= nx; i++)                if(visx[i]) lx[i] -=d;            for(int i = 1; i <= ny; i++)                if(visy[i]) ly[i] += d;                else slack[i] -= d;        }    }}int main(){    int x, y, z, e, cas = 0;    while(scanf("%d%d%d", &n, &m, &e) != EOF)    {        nx = n, ny = m;        for(int i = 1; i <= n; i++)            for(int j = 1; j <= m; j++)                w[i][j] = -INF;        while(e--)        {            scanf("%d%d%d", &x, &y, &z);            if(z >= 0) w[x + 1][y + 1] = z;        }        printf("Case %d: ", ++cas);        KM();        int cnt = 0, ans = 0;        for(int i = 1; i <= ny; i++)            if(linky[i] != -1 && w[linky[i]][i] != -INF)                ans += w[linky[i]][i], cnt++;        if(cnt != nx) ans = -1;        printf("%d\n", ans);    }    return 0;}


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 脸上长痘痘留下的坑怎么办 脸部被打得皮肤怎么办 打脸引起耳朵疼怎么办 被打了耳痛耳鸣怎么办 苹果6视频锁屏怎么办 抠耳朵抠疼了怎么办 图库的相片没了怎么办 遇到打假牌的人怎么办 部队保障卡丢了怎么办 廊坊武警学院取消现役学员怎么办 孩子去当兵联系不上怎么办 军训戴眼镜晒痕怎么办 想进部队体检没过怎么办 大腿跟小腿不直怎么办 腿被车门夹了怎么办 脚出汗穿凉鞋滑怎么办 玩游戏手出汗屏幕滑怎么办 新买的鞋子臭怎么办 当公民利益受到侵犯怎么办 唇钉里面长肉怎么办 宝宝舔了一口酒怎么办 头被玻璃门撞了怎么办 30多了还一事无成 未来怎么办 27岁失业了该怎么办 无业证明不给开怎么办 典型的缺乏运动的肥胖怎么办 30岁了不想结婚怎么办 专家解释欠30万怎么办 欠医院十几万钱怎么办 当你迷茫的时候怎么办 被骗了一年的积蓄怎么办 当兵身高视力都不够怎么办 当兵中途不想当了怎么办 当兵后不想当了怎么办 在泰国想剪头发怎么办 省二证书丢了怎么办 职称计算机级别报错怎么办 科一不会用电脑怎么办 西安科目三挂了怎么办 我有c照想考a照怎么办 叉车证单位不给怎么办