最小费用最大流问题,同POJ2516,此题较之要简单些,容量只为1, 花费为人到屋子的哈密顿距离,且二分匹配中X,Y规模一致。
KM:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
#define maxN 105
#define INF 0X7F7F
short cost[maxN][maxN];
short lx[maxN],ly[maxN];
char visx[maxN],visy[maxN];
short match[maxN];
short slack[maxN];
short minCost;
short N;
bool DFS(short x)
{
short i,diff;
visx[x] = true;
for(i = 1;i <= N;i++)
{
if(!visy[i])
{
diff = lx[x]+ly[i]-cost[x][i];
if(diff == 0)
{
visy[i] = true;
if(match[i] == 0||DFS(match[i]))
{
match[i] = x;
return 1;
}
}
else if(slack[i] > diff)
{
slack[i] = diff;
}
}
}
return 0;
}
int KM()
{
short i,j;
short d;
memset(match,0,sizeof(match));
memset(lx,0X80,sizeof(lx));
memset(ly,0,sizeof(ly));
for(i = 1;i <= N;i++)
{
for(j = 1;j <= N;j++)
{
if(lx[i] < cost[i][j])
{
lx[i] = cost[i][j];
}
}
}
for(i = 1;i <= N;i++)
{
memset(slack,0X7F,sizeof(slack));
while(1)
{
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
if(DFS(i)) //找到增广路径就跳出循环,没找到改标号
{
break;
}
d = INF;
for(j = 1;j <= N;j++)
{
if(!visy[j]&&slack[j] < d)
{
d = slack[j];
}
}
for(j = 1;j <= N;j++)
{
if(visx[j])
{
lx[j] -= d;
}
if(visy[j])
{
ly[j] += d;
}
else
{
slack[j] -= d;
}
}
}
}
minCost = 0;
for(i = 1;i <= N;i++)
{
minCost += cost[match[i]][i];
}
printf("%d\n",-1*minCost);
return 0;
}
int main()
{
int i,j,M;
int mNum,houseNum;
char c;
short mXY[maxN][2],hXY[maxN][2];
while(~scanf("%d%d",&N,&M)&&N)
{
minCost = 0;
memset(cost,0,sizeof(cost));
mNum = houseNum = 1;
getchar();
for(i = 1;i <= N;i++)
{
for(j = 1;j <= M;j++)
{
c = getchar();
if(c == 'm')
{
mXY[mNum][0] = i;
mXY[mNum++][1] = j;
}
else if(c == 'H')
{
hXY[houseNum][0] = i;
hXY[houseNum++][1] = j;
}
}
getchar();
}
N = --houseNum;
for(i = 1;i <= houseNum;i++)
{
for(j = 1;j <= houseNum;j++)
{
cost[i][j] = -1*(abs(mXY[i][0]-hXY[j][0])+abs(mXY[i][1]-hXY[j][1]));
}
}
KM();
}
return 0;
}
SPFA:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
#define maxN 105
#define INF 0X7F7F
int dest;
short capacity[(maxN)<<1][(maxN)<<1];
short cost[(maxN)<<1][(maxN)<<1];
short minCost;
short spfa(short* fa)
{
short i,now;
short minDis[(maxN)<<1];
char vis[(maxN)<<1];
memset(vis,0,sizeof(vis));
memset(minDis,127,sizeof(minDis));
minDis[0] = 0;
queue<short> q;
q.push(0);
vis[0] = true;
while(!q.empty())
{
now = q.front();
q.pop();
vis[now] = false;
for(i = 1;i <= dest;i++)
{
if(capacity[now][i] > 0&&minDis[now]+cost[now][i] < minDis[i])
{
fa[i] = now;
minDis[i] = minDis[now]+cost[now][i];
if(!vis[i])
{
q.push(i);
vis[i] = true;
}
}
}
}
return minDis[dest];
}
int minCost_maxFlow()
{
short x;
short fa[(maxN)<<1];
while(spfa(fa) != INF)
{
x = dest;
while(x)
{
minCost += cost[fa[x]][x];
capacity[fa[x]][x] = 0;
capacity[x][fa[x]] = 1;
x = fa[x];
}
}
printf("%d\n",minCost);
return 0;
}
int main()
{
int i,j,N,M;
int mNum,houseNum;
char c;
short mXY[maxN][2],hXY[maxN][2];
while(~scanf("%d%d",&N,&M)&&N)
{
minCost = 0;
memset(capacity,0,sizeof(capacity));
memset(cost,0,sizeof(cost));
mNum = houseNum = 1;
getchar();
for(i = 1;i <= N;i++)
{
for(j = 1;j <= M;j++)
{
c = getchar();
if(c == 'm')
{
mXY[mNum][0] = i;
mXY[mNum++][1] = j;
}
else if(c == 'H')
{
hXY[houseNum][0] = i;
hXY[houseNum++][1] = j;
}
}
getchar();
}
houseNum--;
dest = (houseNum<<1)|1;
for(i = 1;i <= houseNum;i++)
{
capacity[0][i] = capacity[houseNum+i][dest] = 1;
for(j = 1;j <= houseNum;j++)
{
capacity[i][houseNum+j] = 1;
cost[i][houseNum+j] = abs(mXY[i][0]-hXY[j][0])+abs(mXY[i][1]-hXY[j][1]);
cost[houseNum+j][i] = -1*cost[i][houseNum+j];
}
}
minCost_maxFlow();
}
return 0;
}
Bellman_Ford:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
#define maxN 105
#define maxE 20200
#define INF 0X7F7F
int dest;
short capacity[(maxN)<<1][(maxN)<<1];
short cost[(maxN)<<1][(maxN)<<1];
short edges[maxE][2];
short edgeNum;
short minCost;
int generateEdge()
{
edgeNum = 0;
short i,j;
for(i = 0;i < dest;i++)
{
for(j = 1;j <= dest;j++)
{
if(capacity[i][j] > 0)
{
edges[edgeNum][0] = i;
edges[edgeNum++][1] = j;
}
}
}
return 1;
}
short bellman_ford(short* fa)
{
short i,j;
short x,y;
short minDis[(maxN)<<1];
char IsRelax;
memset(minDis,0x7F,sizeof(minDis));
minDis[0] = 0;
for(i = 0;i < dest;i++)
{
IsRelax = false;
for(j = 0;j < edgeNum;j++)
{
x = edges[j][0];
y = edges[j][1];
if(minDis[y] > minDis[x]+cost[x][y])
{
fa[y] = x;
minDis[y] = minDis[x]+cost[x][y];
IsRelax = true;
}
}
if(!IsRelax)
break;
}
return minDis[dest];
}
int minCost_maxFlow()
{
short x;
short fa[(maxN)<<1];
while(generateEdge()&&bellman_ford(fa) != INF)
{
x = dest;
while(x)
{
minCost += cost[fa[x]][x];
capacity[fa[x]][x] = 0;
capacity[x][fa[x]] = 1;
x = fa[x];
}
}
printf("%d\n",minCost);
return 0;
}
int main()
{
int i,j,N,M;
int mNum,houseNum;
char c;
short mXY[maxN][2],hXY[maxN][2];
while(~scanf("%d%d",&N,&M)&&N)
{
minCost = 0;
memset(capacity,0,sizeof(capacity));
memset(cost,0,sizeof(cost));
mNum = houseNum = 1;
getchar();
for(i = 1;i <= N;i++)
{
for(j = 1;j <= M;j++)
{
c = getchar();
if(c == 'm')
{
mXY[mNum][0] = i;
mXY[mNum++][1] = j;
}
else if(c == 'H')
{
hXY[houseNum][0] = i;
hXY[houseNum++][1] = j;
}
}
getchar();
}
houseNum--;
dest = (houseNum<<1)|1;
for(i = 1;i <= houseNum;i++)
{
capacity[0][i] = capacity[houseNum+i][dest] = 1;
for(j = 1;j <= houseNum;j++)
{
capacity[i][houseNum+j] = 1;
cost[i][houseNum+j] = abs(mXY[i][0]-hXY[j][0])+abs(mXY[i][1]-hXY[j][1]);
cost[houseNum+j][i] = -1*cost[i][houseNum+j];
}
}
minCost_maxFlow();
}
return 0;
}