版权声明:转载注明下出处就行了。 https://blog.csdn.net/LJD201724114126/article/details/83999971
参考链接:https://blog.csdn.net/sixdaycoder/article/details/47720471
https://www.cnblogs.com/Lanly/p/6291214.html
https://www.cnblogs.com/Mychael/p/8994980.html
题目:hdu 2255
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define INF 0x3f3f3f3f
const int maxn=305;
int match[maxn],lx[maxn],ly[maxn],slack[maxn];
int G[maxn][maxn];
bool visx[maxn],visy[maxn];
int n,nx,ny;
bool findpath(int x)
{
int tempdelta;
visx[x]=1;
for(int y=0;y<ny;y++)
{
if(visy[y]) continue;
tempdelta=lx[x]+ly[y]-G[x][y];
if(tempdelta==0){
visy[y]=1;
if(match[y]==-1||findpath(match[y])){
match[y]=x;
return true;
}
}
else if(slack[y]>tempdelta)
slack[y]=tempdelta;
}
return false;
}
void KM()
{
for(int x=0;x<nx;x++)
{
for(int j=0;j<ny;j++) slack[j]=INF;
while(1)
{
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
if(findpath(x)) break;
int delta=INF;
for(int j=0;j<ny;j++)
if(!visy[j]) delta=min(delta,slack[j]);
for(int i=0;i<nx;i++)
{
if(visx[i]) lx[i]-=delta; ///已匹配点处理
if(visy[i]) ly[i]+=delta;
else slack[i]-=delta;
}
}
}
}
void solve()
{
memset(match,-1,sizeof(match));
memset(ly,0,sizeof(match));
for(int i=0;i<nx;i++)
{
lx[i]=-INF;
for(int j=0;j<ny;j++)
lx[i]=max(lx[i],G[i][j]);
}
KM();
}
int main()
{
while(~scanf("%d",&n))
{
nx=ny=n;
for(int i=0;i<nx;i++)
for(int j=0;j<ny;j++)
scanf("%d",&G[i][j]);
solve();
int ans=0;
for(int i=0;i<ny;i++)
{
if(match[i]!=-1)
ans+=G[match[i]][i];
}
printf("%d\n",ans);
}
}
题目:hdu 1533
题意:给幅图,有相同的人和相同的房子,让你把每个人移动到房子里,每移动一个单位,要出一块钱,问你:将所有人移动到房子里,最少移动步数是多少?
题解:直接建个二分图。
///题目要的是最短路,所以我们把值取负,就相当于km算法求了
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define INF 0x3f3f3f3f
const int maxn=110;
char op[maxn][maxn];
int match[maxn],lx[maxn],ly[maxn],slack[maxn];
bool visx[maxn],visy[maxn];
struct node{
int x,y;
node(){}
node(int _x,int _y){
x=_x;y=_y;
}
}house[maxn],people[maxn]; ///存储房子,人的位置
int G[maxn][maxn],nx,ny;
bool findpath(int x)
{
int tempdelta;
visx[x]=1;
for(int y=0;y<ny;y++)
{
if(visy[y]) continue;
tempdelta=lx[x]+ly[y]-G[x][y];
if(tempdelta==0)
{
visy[y]=1;
if(match[y]==-1||findpath(match[y])){
match[y]=x;
return 1;
}
}
else if(slack[y]>tempdelta) slack[y]=tempdelta;
}
return false;
}
void KM()
{
for(int x=0;x<nx;x++)
{
// printf("asdf");
for(int j=0;j<ny;j++) slack[j]=INF;
while(1)
{
// printf("tiao");
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
if(findpath(x)) break;
int delta=INF;
for(int j=0;j<ny;j++)
if(!visy[j]) delta=min(delta,slack[j]);
for(int i=0;i<nx;i++)
if(visx[i]) lx[i]-=delta;
for(int j=0;j<ny;j++)
{
if(visy[j]) ly[j]+=delta;
else slack[j]-=delta;
}
}
}
}
void solve() ///模板了
{
memset(match,-1,sizeof(match));
memset(ly,0,sizeof(ly));
for(int i=0;i<nx;i++)
{
lx[i]=-INF;
for(int j=0;j<ny;j++)
lx[i]=max(lx[i],G[i][j]);
}
KM();
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m))
{
if(m==0&&n==0) break;
for(int i=0;i<n;i++)
scanf("%s",op[i]);
nx=ny=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
if(op[i][j]=='m') people[nx++]=node(i,j); ///存储点
else if(op[i][j]=='H') house[ny++]=node(i,j);
}
memset(G,0,sizeof(G));
for(int i=0;i<nx;i++)
{
for(int j=0;j<ny;j++) ///建图
{
G[i][j]=-(abs(house[j].x-people[i].x)+abs(house[j].y-people[i].y));
}
}
solve();
int ans=0;
for(int i=0;i<ny;i++)
{
if(match[i]!=-1) ans+=G[match[i]][i];
}
printf("%d\n",-ans);
}
return 0;
}