您的位置:首页 > 编程语言 > Go语言

hdu 1533 Going Home (最小费用最大流)

2015-07-26 21:16 621 查看
/*
题意:
给定一个N*M的地图,地图上有若干个man和house,且man与house的数量一致。
man每移动一格需花费$1(即单位费用=单位距离)
,一间house只能入住一个man。现在要求所有的man都入住house,求最小费用。

把man作为一个顶点集合U,house作为另一个顶点集合V,把U中所有点到V中所有点连线,
费用cost[u][v]为abs(△x)+abs(△y),反向弧费用cost[v][u]= -cost[u][v],
容量cap[u][v]=1,构成一个多源多汇的二分图。
由于每一个多源多汇的网络流都必有一个与之对应的单源单汇的网络流,
为了便于解题,由此构造一个超级源s和超级汇t,超级源s与U中所有点相连,
费用cost[s][u]=0(这是显然的)
容量cap[s][u]=1;V中所有点与超级汇t相连,费用cost[v][t]=0(这是显然的),容量cap[t][v]=1。
*/
# include <stdio.h>
# include <algorithm>
# include <stack>
# include <queue>
# include <string.h>
using namespace std;
# define MAXM 500010//边
# define MAXN 10010//点
# define INF 0x3fffff
struct node
{
int x;
int y;
};
node cotm[5010],coth[5010];
struct Edge
{
int to,next,cap,flow,cost;
} edge[MAXM];
int head[MAXN],tol;
int pre[MAXN],dis[MAXN];
bool vis[MAXN];
int N;//节点总个数,节点编号从0~N-1
void init(int n)
{
N = n;
tol = 0;
memset(head,-1,sizeof (head));
}
void addedge (int u,int v,int cap,int cost)
{
edge[tol].to = v;
edge[tol].cap = cap;
edge[tol].cost = cost;
edge[tol].flow = 0;
edge[tol].next = head[u];
head[u] = tol++;
edge[tol].to = u;
edge[tol].cap = 0;
edge[tol].cost = -cost;
edge[tol].flow = 0;
edge[tol].next = head[v];
head[v] = tol++;
}
bool spfa(int s,int t)
{
queue<int>q;
for(int i = 0; i < N; i++)
{
dis[i] = INF;
vis[i] = false;
pre[i] = -1;
}
dis[s] = 0;
vis[s] = true;
q.push(s);
while(!q.empty())
{
int u = q.front();
q.pop();
vis[u] = false;
for(int i = head[u]; i !=  -1; i = edge[i]. next)
{
int v = edge[i]. to;
if(edge[i].cap > edge[i].flow &&
dis[v] > dis[u] + edge[i]. cost )
{
dis[v] = dis[u] + edge[i]. cost;
pre[v] = i;
if(!vis[v])
{
vis[v] = true;
q.push(v);
}
}
}
}
if(pre[t] == -1)return false;
else return true;
}
//返回的是最大流,cost存的是最小费用
int minCostMaxflow(int s,int t,int &cost)
{
int flow = 0;
cost = 0;
while(spfa(s,t))
{
int Min = INF;
for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])
{
if(Min > edge[i].cap - edge[i]. flow)
Min = edge[i].cap - edge[i].flow;
}
for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])
{
edge[i].flow += Min;
edge[i^1].flow -= Min;
cost += edge[i]. cost * Min;
}
flow += Min;
}
return flow;
}
int main()
{
int n,m,cot1,cot2,i,j;
char a[110][110];
while(~scanf("%d%d",&n,&m),n+m)
{
cot1=0;
cot2=0;
for(i=0; i<n; i++)
scanf("%s",a[i]);
for(i=0; i<n; i++)
{
for(j=0; j<m; j++)
{
if(a[i][j]=='m')
{
cot1++;
cotm[cot1].x=i+1;
cotm[cot1].y=j+1;

}
else if(a[i][j]=='H')
{
cot2++;
coth[cot2].x=i+1;
coth[cot2].y=j+1;

}
}

}
//     printf("%d %d\n",cot1,cot2);
int sa=0;//超级源点
int ed=cot1+cot2+1;//超级汇点
init(ed+1);//总节点数
for(i=1; i<=cot1; i++)
addedge(sa,i,1,0);
for(i=1; i<=cot2; i++)
addedge(i+cot1,ed,1,0);
for(i=1; i<=cot1; i++)
{
for(j=1; j<=cot2; j++)
{
int x=abs(cotm[i].x-coth[j].x)+abs(cotm[i].y-coth[j].y);
addedge(i,j+cot1,1,x);
}
}
int cost;
int aa=minCostMaxflow(sa,ed,cost);
printf("%d\n",cost);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: