POJ-2195 Going Home 最小权值匹配
生活随笔
收集整理的這篇文章主要介紹了
POJ-2195 Going Home 最小权值匹配
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
題意:給定一個(gè)網(wǎng)格圖,圖上有一些人要到一些房子當(dāng)中去,人和房子的數(shù)量一樣多,人和房子的曼哈頓距離作為行走的開銷,問所有人走到房子中的最小開銷。
解法:將人和房子之間兩兩之間建立帶權(quán)邊,權(quán)值為曼哈頓距離的相反數(shù),這樣問題就轉(zhuǎn)化為最大權(quán)值匹配問題。
代碼如下:
#include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; const int INF = 0x3f3f3f3f;int N, M, iM, iH; int w[105][105]; // 記錄邊權(quán) int match[105]; // 保留匹配邊 int lx[105], ly[105]; // 記錄頂點(diǎn)可行標(biāo) int sx[105], sy[105]; // 標(biāo)記頂點(diǎn)是否在交錯(cuò)樹中 int slack[105]; // 松弛函數(shù),用于保留交錯(cuò)樹中Y部節(jié)點(diǎn)的最小d值 char mp[105][105]; // 保留原始圖形 struct Node {int x, y; }nM[105], nH[105];void build() {memset(w, 0, sizeof (w)); // 該題中不可能出現(xiàn)距離為0的情況,添加負(fù)號后所有權(quán)值都將小于0 for (int i = 1; i < iM; ++i) { // iM == iHfor (int j = 1; j < iM; ++j) { // 通過添加負(fù)號將最小權(quán)值匹配轉(zhuǎn)化為最大權(quán)值匹配w[i][j] = -abs(nM[i].x - nH[j].x)-abs(nM[i].y - nH[j].y);}} }int path(int u) {sx[u] = 1; // S集合中添加元素for (int i = 1; i < iM; ++i) {if (sy[i]) continue;int t = lx[u]+ly[i] - w[u][i];if (!t) { // 如果該邊屬于等價(jià)子圖中的邊sy[i] = 1; // T集合中添加元素if (!match[i] || path(match[i])) {match[i] = u;return 1;}} else { // 沒有被加入到T集合中,并且與u頂點(diǎn)無法增廣 slack[i] = min(slack[i], t);}}return 0; }int KM() {// 首先初始化可行標(biāo)memset(ly, 0, sizeof (ly));memset(lx, 0x80, sizeof (lx));for (int i = 1; i < iM; ++i) {for (int j = 1; j < iM; ++j) {lx[i] = max(lx[i], w[i][j]);// 取所有邊中權(quán)值最大的邊作為該頂點(diǎn)的可行標(biāo)值 }}memset(match, 0, sizeof (match));for (int i = 1; i < iM; ++i) { // 針對每一個(gè)頂點(diǎn)進(jìn)行一次增廣,如果無法完成就通過修改可行標(biāo)來完成 for (int j = 1; j < iM; ++j) {slack[j] = INF;}while (1) {memset(sx, 0, sizeof (sx));memset(sy, 0, sizeof (sy));if (path(i)) break;int d = INF;for (int j = 1; j < iM; ++j) {if (!sy[j]) d = min(d, slack[j]); } for (int j = 1; j < iM; ++j) {if (sx[j]) lx[j] -= d;}for (int j = 1; j < iM; ++j) {if (sy[j]) ly[j] += d;else slack[j] -= d;}}}int ret = 0;for (int i = 1; i < iM; ++i) {ret += w[match[i]][i];}return -ret; }int main() {while (scanf("%d %d", &N, &M), N|M) {iM = iH = 1;for (int i = 0; i < N; ++i) {scanf("%s", mp[i]);for (int j = 0; j < M; ++j) {if (mp[i][j] == 'm') {nM[iM].x = i, nM[iM++].y = j;} else if (mp[i][j] == 'H') {nH[iH].x = i, nH[iH++].y = j;}}}build();printf("%d\n", KM());}return 0; }
?
轉(zhuǎn)載于:https://www.cnblogs.com/Lyush/archive/2013/04/09/3010834.html
總結(jié)
以上是生活随笔為你收集整理的POJ-2195 Going Home 最小权值匹配的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用C#调用Python脚本,带参数列表
- 下一篇: CodeDom 笔记整理