?? 2195(1) km.cpp
字號:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 100
int HCount, MCount;
struct Pos
{
int x;
int y;
};
struct Pos* Man[SIZE];
struct Pos* House[SIZE];
int Weight[SIZE][SIZE];
int XSize, YSize;
int dog[SIZE], god[SIZE];
bool chart[SIZE][SIZE];
template<class T>
inline T Abs(T a)
{
if (a < 0)
return (-a);
return a;
}
bool findBestMatch()
{
int i, j, k;
int X[SIZE], Y[SIZE];
for (i = 0; i < XSize; ++i){
for(j = 0; j < YSize; ++j){
if (j == 0) X[i] = Weight[i][j];
else
X[i] = (X[i] > Weight[i][j] ? X[i]:Weight[i][j]);
}
dog[i] = -1;
}
for (i = 0; i < YSize; ++i){
Y[i] = 0;
god[i] = -1;
}
k = 0;
while (k < XSize){
while (dog[k] == -1){
for (i = 0; i < XSize; ++i){//初始化等式子圖,其實只需初始x~y(x屬于S,y屬于 Y - t)
for (j = 0; j < YSize; ++j){
if (X[i] + Y[j] == Weight[i][j])
chart[i][j] = true;
else
chart[i][j] = false;
}
}
int queue[SIZE], Begin = 0, End = 0;//建立一個隊列,end前為己匹配,后為未匹配
int trace[SIZE];
for (i = 0; i < YSize; ++i){//Pick k to S:(trace),初始化T為空
queue[i] = i;
l1: if (chart[k][queue[i]]){
trace[queue[i]] = k;
j = queue[i]; queue[i] = queue[End]; queue[End++] = j;
}
else trace[i] = -1;
} //queue[End]前為有匹配的yi
while (Begin < End){//找增廣路BFS
l2: if (god[queue[Begin]] == -1) break; //X(k) 的鄰接點{yi}己被先前結點X(i<k)匹配 最關鍵的一步
for (i = End; i < YSize; ++i){//x(k)搶占{yi},并為X(i<k)重選搭檔,從End后的{y}中選取,即從未匹配集{yi}的點中選
l3: if (chart[ god[ queue[Begin]] ][queue[i]]){
trace[queue[i]] = god[queue[Begin]]; //按原路擴充交錯路 M -> M',保存在trace
j = queue[i]; queue[i] = queue[End]; queue[End++] = j; //X(i<k)重配了End后的{y}中的Yj,則End++,讓Yj加入{yi},即加入己匹配隊列,避免被重用
}
}
++Begin;
}
l4: if (Begin < End){//找到增廣路
i = queue[Begin];
l5: while (trace[i] != k){//如果X(k)的直接Y(i)還沒被匹配則不用回溯,否則回溯重構匹配圖
god[i] = trace[i];
j = dog[god[i]]; dog[god[i]] = i; i = j;
}
god[i] = k;
dog[k] = i;
}
else{//d = min{l(x)+l(y)-w(x,y) | x 屬于 S,y 屬于 T,即x,Y - {y}屬于 M'}
if (End == YSize) break;
int min;
for (i = End; i < YSize; ++i){
int d = X[k] + Y[queue[i]] - Weight[k][queue[i]];
if (i == End || min > d) min = d;
}
for (i = 0; i < End; ++i){//在BFS搜索時就可邊記錄min
for (j = End; j < YSize; ++j){
int d = X[ god[queue[i]] ] + Y[queue[j]] - Weight[ god[queue[i]] ][queue[j]];
if (min > d) min = d;
}
}
for (i = 0; i < End; ++i){//修改頂標
X[ god[queue[i]] ] -= min;
Y[queue[i]] += min;
}
X[k] -= min;
}//找不到增廣路,降低X(屬于S)的頂標,加入新的y 點
}//while (dog[k] == -1)
if (dog[k] == -1) return false;
++k;
}//while (k < XSize)
return true;
}
int search()//在abs()前加負號和返回負sum,是求最小權值完美匹配
{
XSize = MCount;
YSize = HCount;
int i, j;
for (i = 0; i < XSize; ++i)
for (j = 0; j < YSize; ++j)
Weight[i][j] = -Abs(House[j]->x - Man[i]->x) - Abs(House[j]->y - Man[i]->y);
int sum = 0;
if (findBestMatch()){
for (i = 0; i < XSize; ++i)
sum += Weight[i][dog[i]];
}
return -sum;//返回最小值sum的相反數為最大
}
int main()
{
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
int i, j, m, n;
char ch;
for (i = 0; i < SIZE; ++i){
Man[i] = (struct Pos*)malloc(sizeof(struct Pos));
House[i] = (struct Pos*)malloc(sizeof(struct Pos));
}
while (scanf("%d %d", &n, &m), n){
HCount = 0;
MCount = 0;
for (i = 0; i < n; ++i){
for (j = 0; j < m; ++j){
scanf(" %c", &ch);
if (ch == 'H'){
House[HCount]->x = i;
House[HCount]->y = j;
++HCount;
}
else if (ch == 'm'){
Man[MCount]->x = i;
Man[MCount]->y = j;
++MCount;
}
}
}
printf("%d\n", search());
}
for (i = 0; i < SIZE; ++i){
free(Man[i]);
free(House[i]);
}
return 0;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -