1047 - Best couple 好题~

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;
}
时间: 2024-10-09 21:10:02

1047 - Best couple 好题~的相关文章

POJ百道水题列表

以下是poj百道水题,新手可以考虑从这里刷起 搜索1002 Fire Net1004 Anagrams by Stack1005 Jugs1008 Gnome Tetravex1091 Knight Moves1101 Gamblers1204 Additive equations 1221 Risk1230 Legendary Pokemon1249 Pushing Boxes 1364 Machine Schedule1368 BOAT1406 Jungle Roads1411 Annive

HDU1568斐波那契推理

Fibonacci Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4512    Accepted Submission(s): 2068 Problem Description 2007年到来了.经过2006年一年的修炼,数学神童zouyu终于把0到100000000的Fibonacci数列(f[0]=0,f[1]=1;f[i] =

zoj题目分类

饮水思源---zoj 转载自:http://bbs.sjtu.edu.cn/bbscon,board,ACMICPC,file,M.1084159773.A.html 注:所有不是太难的题都被归成了“简单题”,等到发现的时候已经太晚了,我太死脑筋 了……:( 有些题的程序我找不到了,555……:( SRbGa的题虽然都很经典……但是由于其中的大部分都是我看了oibh上的解题报告后做 的,所以就不写了…… 题目排列顺序没有规律……:( 按照个人感觉,最短路有的算做了DP,有的算做了图论. 有些比较

1047. Remove All Adjacent Duplicates In String做题报告

题目链接: Remove All Adjacent Duplicates In String 题目大意: 删除字符串中的所有相邻字符 做题报告: (1)该题涉及的算法与数据结构 栈 (2)自己的解答思路+代码+分析时间和空间复杂度 Input: "abbaca" Output: "ca"          思路:使用栈,对字符串遍历,进行入栈出栈操作.如果栈空或者遍历到的该字符与栈顶元素不同则入栈,否则(即遍历到的该字符与栈顶元素相同)出栈.最后,栈存的字符就是我们

周赛C题 LightOJ 1047 (DP)

C - C Time Limit:500MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu Description The people of Mohammadpur have decided to paint each of their houses red, green, or blue. They've also decided that no two neighboring houses will be painted

北大ACM题库习题分类与简介(转载)

在百度文库上找到的,不知是哪位大牛整理的,真的很不错! zz题 目分类 Posted by fishhead at 2007-01-13 12:44:58.0 -------------------------------------------------------------------------------- acm.pku.edu.cn 1. 排序 1423, 1694, 1723, 1727, 1763, 1788, 1828, 1838, 1840, 2201, 2376, 23

PAT 乙级 1047 编程团体赛(20) C++版

1047. 编程团体赛(20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 编程团体赛的规则为:每个参赛队由若干队员组成:所有队员独立比赛:参赛队的成绩为所有队员的成绩和:成绩最高的队获胜. 现给定所有队员的比赛成绩,请你编写程序找出冠军队. 输入格式: 输入第一行给出一个正整数N(<=10000),即所有参赛队员总数.随后N行,每行给出一位队员的成绩,格式为:"队伍编号-队员编号 成绩",

poj50题

POJ推荐50题1.标记“难”和“稍难”的题目可以看看,思考一下,不做要求,当然有能力的同学可以直接切掉.2.标记为A and B的题目是比较相似的题目,建议大家两个一起做,可以对比总结,且二者算作一个题目.3.列表中大约有70个题目.大家选做其中的50道,且每类题目有最低数量限制.4.这里不少题目在BUPT ACM FTP上面都有代码,请大家合理利用资源.5.50个题目要求每个题目都要写总结,养成良好的习惯.6.这个列表的目的在于让大家对各个方面的算法有个了解,也许要求有些苛刻,教条,请大家谅

poj题库分类

初期:一.基本算法:     (1)枚举. (poj1753,poj2965)     (2)贪心(poj1328,poj2109,poj2586)     (3)递归和分治法.     (4)递推.     (5)构造法.(poj3295)     (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)二.图算法:     (1)图的深度优先遍历和广度优先遍历.     (2)最短路径算法(dijkstra,bellman-ford,floyd,hea