您的位置:首页 > 理论基础 > 计算机网络

最小费用最大流;HDU1533

2015-08-03 10:45 561 查看
//第一次写费用流,有些地方还是不太懂,但是思路很简单。
//建立伴随网络后,每次用spfa找最短路然后增广就好了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#define maxN 300
#define maxM 10005
#define INF 0xffffff
using namespace std;

struct node
{
int c;//容量
int f;//流量
int c_f;//残留容量
int val;//价值
}G[maxN][maxN];
int n,m;
int pre[maxM];//记录前驱点
int dist[maxM];//spfa记录距离
char coord[maxN][maxN];//坐标集
int inq[maxM];
int min_f;
int sum;
int vertex;

struct House
{
int x;
int y;
}house[maxN];

struct Man
{
int x;
int y;
}man[maxN];

void init()
{
sum=0;
int mcase,hcase;
mcase=hcase=0;
int i,j;
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
cin>>coord[i][j];
if(coord[i][j]=='m'){
mcase++;
man[mcase].x=i;
man[mcase].y=j;
}
if(coord[i][j]=='H'){
hcase++;
house[hcase].x=i;
house[hcase].y=j;
}
}
}
vertex=hcase+mcase+1;
for(int u=0;u<=vertex;u++)
{
for(int v=0;v<=vertex;v++)
{
G[u][v].c=G[v][u].c=0;
G[u][v].f=G[v][u].f=0;
G[u][v].c_f=G[v][u].c_f=0;
G[u][v].val=G[v][u].val=INF;
}
}
for(i=1;i<=mcase;i++)
{
G[0][i].val=0;
G[0][i].c_f=G[0][i].c=1;
for(j=1;j<=hcase;j++)
{
int len=abs((house[j].x-man[i].x))+abs(house[j].y-man[i].y);
G[i][mcase+j].val=len;
G[i][mcase+j].c=1;
G[i][mcase+j].c_f=1;
G[mcase+j][vertex].c=1;
G[mcase+j][vertex].c_f=1;
G[mcase+j][vertex].val=0;
}
}
}

void spfa(int s)
{
queue<int> q;
int i;
for(i=0;i<maxN;i++)
{
dist[i]=INF;
pre[i]=-1;
inq[i]=0;
}
dist[s]=0;
inq[i]=1;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
inq[u]=0;
for(i=0;i<=vertex;i++)
{
if(G[u][i].c_f==0) continue;
if(G[u][i].val==INF) G[u][i].val=-G[i][u].val;
//不太懂
if(dist[i]>dist[u]+G[u][i].val)
{
dist[i]=dist[u]+G[u][i].val;
pre[i]=u;
if(!inq[i])
{
q.push(i);
inq[i]=1;
}
}
}
}
}

void argument(int s,int t)
{
spfa(s);
int v;
while(pre[t]!=-1)
{
int u=pre[t];
v=t;
sum+=dist[v];
min_f=INF;
while(u!=-1)
{
if(G[u][v].c_f<min_f)
min_f=G[u][v].c_f;
v=u;
u=pre[v];
}
u=pre[t];v=t;
while(u!=-1)
{
G[u][v].f+=min_f;
G[v][u].f=-G[u][v].f;
G[u][v].c_f=G[u][v].c-G[u][v].f;
G[v][u].c_f=G[v][u].c-G[v][u].f;
v=u;
u=pre[v];
}
spfa(s);
}
}

int main()
{
while(cin>>n>>m)
{
if(n==0&&m==0) break;
init();
argument(0,vertex);
cout<<sum<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  网络流