1047

http://www.ifrog.cc/acm/problem/1047

思路很简单,跑一发floyd,然后再用km。

但是问题来了,这个有可能n != m。那怎么办?

其实可以补上一些不存在的点。来使得n = m。他们的权值就设置为0就好了。意思就是这些人的搭配,是对答案没有贡献的。注意不能设置为-inf。因为补上的那些点也是必须要选人的,只不过他们选了人,相当于没选而已(权值不存在。)如果设置为-inf的那些,那么他们就会把答案改了。

还有一个小trick的就是,一开始,我是把本来地图上的-1的那些点,更改为inf的,inf表示不连通,那么直接floyd就可以了不用特判那么多。那么问题又来了。如果跑了floyd后,还是不连通,那怎么办?他们的权值可是inf啊。组成新图的时候,同时也是需要把他们的权值设置为0的,也就是相当于没选。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;

#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
const int maxn = 1e2 + 20;
int e[maxn][maxn];
int TE[2 * maxn][2 * maxn];
int match[maxn];//match[col] = row
int vx[maxn],vy[maxn];
int fx[maxn],fy[maxn];
int n, m;
int dfs (int u) {
    vx[u]=1;
    int i;
    for (i=1; i<=m; i++) { //筛选n个 导航员 col的值
        if (vy[i]==0&&fx[u]+fy[i]==e[u][i]) {
            vy[i]=1;
            if (match[i]==0||dfs(match[i])) {
                match[i]=u;// match[col]=row;
                return 1;//搭配成功
            }
        }
    }
    return 0;//我找不到啊,后面,就会执行km
}
void do_km() { //
    int i,j;
    int d=inf;
    for (i=1; i<=n; i++) { //遍历每一个驾驶员 row的值
        if (vx[i]==1) {
            for (j=1; j<=m; j++) { //对他进行遍历导航员 col的值
                if (!vy[j]) {
                    if (d>(fx[i]+fy[j]-e[i][j])) {
                        d=fx[i]+fy[j]-e[i][j];
                    }
                }
            }
        }
    }
    for (i=1; i<=n; i++) {
        if (vx[i]==1) {
            fx[i] -= d;
            vx[i]=0;//请0
        }
        if (vy[i]==1) { //
            fy[i] += d;
            vy[i]=0;//情0
        }
    }
    return ;
}
int anskm() {
    memset (vx,0,sizeof(vx));
    memset (vy,0,sizeof(vy));
    memset (fx,0,sizeof(fx));
    memset (fy,0,sizeof(fy));
    memset (match,0,sizeof(match));
    //km算法的一部分,先初始化fx,fy
    for (int i=1; i<=n; i++) { //遍历每一个驾驶员 row的值
        fy[i]=0;
        fx[i]= -inf;//无穷小
        for (int j=1; j<=m; j++) { //遍历每一个导航员 col的值
            if (fx[i]<e[i][j]) { //默契值
                fx[i]=e[i][j];
            }
        }
    }
    for (int i=1; i<=n; i++) { //遍历每一个驾驶员 row的值
        memset (vx,0,sizeof(vx));
        memset (vy,0,sizeof(vy));
        while (!dfs(i)) {//如果他找不到搭配,就实现km算法
            do_km();//km完后,还是会对这个想插入的节点进行dfs的,因为他还没搭配嘛
        }
//        if (t == m) break;
    }
    int ans=0;
    for (int i=1; i<=m; i++) //遍历导航员,col的值
        ans += e[match[i]][i];//输入的row是驾驶员,col是导航员
    //match[i]:导航员i和驾驶员match[i]搭配了              match[col]=row;
    return ans;
}

void work() {
    memset(TE, 0, sizeof TE);
    memset(e, 0, sizeof e);
    cin >> n >> m;
    for (int i = 1; i <= n + m; ++i) {
        for (int j = 1; j <= n + m; ++j) {
            cin >> TE[i][j];
            if (TE[i][j] == -1) TE[i][j] = inf;
        }
    }
    for (int k = 1; k <= n + m; ++k) {
        for (int i = 1; i <= n + m; ++i) {
            for (int j = 1; j <= n + m; ++j) {
                if (TE[i][j] > TE[i][k] + TE[k][j]) {
                    TE[i][j] = TE[i][k] + TE[k][j];
                }
            }
        }
    }
//    for (int i = 1; i <= n + m; ++i) {
//        for (int j = 1; j <= n + m; ++j) {
//            cout << TE[i][j] << " ";
//        }
//        cout << endl;
//    }
//    cout << endl;

    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            e[i][j] = TE[i][n + j];
            if (e[i][j] == inf) {
                e[i][j] = 0; //不联通,要用0代替
            }
        }
    }
    if (n > m) {
        for (int i = 1; i <= n; ++i) {
            for (int j = m + 1; j <= n; ++j) {
                e[i][j] = 0;
            }
        }
        m = n;
    } else if (n < m) {
        for (int i = n + 1; i <= m; ++i) {
            for (int j = 1; j <= m; ++j) {
                e[i][j] = 0;
            }
        }
        n = m;
    }
    cout << anskm() << endl;
}
int main() {
#ifdef local
    freopen("data.txt","r",stdin);
#endif
    IOS;
    int t;
    cin >> t;
    while (t--) work();
    return 0;
}
原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6034739.html