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