HDU 2448 Mining Station on the Sea(Floyd+最优匹配)
http://acm.hdu.edu.cn/showproblem.php?pid=2448
题意:
给你一个由N个港口和M个海上油田构成的连通无向图(给出了图中所有的边和权值),现在给你N个船所在的油田编号,问你让这N条船,每条都回到1个港口去(每个港口最多只能容纳一条船),问你这N条船行走的总距离最短是多少?
分析:
其实每条船回到任意一个港口去都有一个距离(用Floyd算法算出的最短距离). 建立二分图: 我们把二分图左边放N个港口,右边放N条船,如果第j条船到第i个港口的距离为x,那么就在右j点与左i点之间连一条权值为x的边.
最终答案即为求 该二分图的最优匹配权值是多少?因为原问题N条船回到N个对应的港口行走总最短距离与现问题二分最优匹配的权值是一一对应的关系.(仔细验证一下,看看是不是一一对应的关系,每一个船只靠岸方案对应了一个二分图的匹配方案
, 每一个二分图的匹配方案对应了一个船只靠岸方案)
注意:本题求得是最小花费,而最优匹配求得是最大值.所以我们需要把所有二分图的边权值取负.且港口到油田是单向路径,一定不能添加双向边,因为添加了双向边,会把港口作为中转站.
AC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100+5;
struct Max_Match
{
int n,W[maxn][maxn];
int Lx[maxn],Ly[maxn];
bool S[maxn],T[maxn];
int left[maxn];
bool match(int i)
{
S[i]=true;
for(int j=1;j<=n;j++)if(Lx[i]+Ly[j]==W[i][j] && !T[j])
{
T[j]=true;
if(left[j]==-1 || match(left[j]))
{
left[j]=i;
return true;
}
}
return false;
}
void update()
{
int a=1<<30;
for(int i=1;i<=n;i++)if(S[i])
for(int j=1;j<=n;j++)if(!T[j])
a=min(a, Lx[i]+Ly[j]-W[i][j]);
for(int i=1;i<=n;i++)
{
if(S[i]) Lx[i] -=a;
if(T[i]) Ly[i] +=a;
}
}
int solve(int n)
{
this->n=n;
memset(left,-1,sizeof(left));
for(int i=1;i<=n;i++)
{
Lx[i]=Ly[i]=0;
for(int j=1;j<=n;j++)
Lx[i]=max(Lx[i],W[i][j]);
}
for(int i=1;i<=n;i++)
{
while(true)
{
for(int j=1;j<=n;j++) S[j]=T[j]=false;
if(match(i)) break;
else update();
}
}
int ans=0;
for(int i=1;i<=n;i++)
ans += W[left[i]][i];
return -ans;//注意取负数
}
}KM;
#define INF 1e9
int dist[300+10][300+10];
void floyd(int n)
{
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(dist[i][k]< INF && dist[k][j]<INF)
dist[i][j] = min(dist[i][j], dist[i][k]+dist[k][j]);
}
int main()
{
int n,m,k,p;
int station_id[maxn];
while(scanf("%d%d%d%d",&n,&m,&k,&p)==4)
{
for(int i=1;i<=n;i++)
scanf("%d",&station_id[i]);
for(int i=1;i<=n+m;i++)
for(int j=1;j<=n+m;j++)
dist[i][j]= i==j?0:INF;
while(k--)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
dist[u+n][v+n]=dist[v+n][u+n]=w;
}
while(p--)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
dist[u][v+n]=w;//港口到油田是单向的
}
floyd(n+m);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
KM.W[i][j] = -dist[i][station_id[j]+n];//注意取负数
printf("%d\n",KM.solve(n));
}
return 0;
}
分享到:
相关推荐
hdu 1695 GCD(欧拉函数+容斥原理).docx
acm hdu as easy as a+b
ACM题库,一些题目和答案,以及解题报告,传上来共享
本人准备2020年保研机试时刷的题目(虽然最后机试取消了,...来自某中流985,在HDU和vjudge平台上大概刷了400道。本文件地图(excel表格)包含了绝大部分我刷过的题目,笔记中具有思路、代码、总结和心得。 大佬勿入!
杭电ACM课件2014版之(HDUACM2010版_13)二分匹配及其应用
HDU二分匹配及其应用,此PPT是刘春英老师版权所有, 特此贡献给广大编程爱好者,特别是对于ACMer
HDU的1250,主要是利用高精度加法,但是代码有点繁琐,效率不是很高
杭电OnlineJudge 200-2099的解题报告
300+ AC 代码 。 大数 , 线段树 , 字符串 , dp.....
杭电ACMhdu1163
HDU1059的代码
hdu1001解题报告
hdu 1574 passed sorce
有题,有解题思路,有解题代码 hdu2516、poj1067和hdu1527、hdu2177、hdu2176等等
HDU的一题........HDU DP动态规
hdu acm 教案 搜索入门 hdu acm 教案 搜索入门
hdu2101AC代码
For a positive integer n, let’s denote function f(n,m) as the m-th smallest integer x that x>n and gcd(x,n)=1. For example, f(5,1)=6 and f(5,5)=11. You are given the value of m and (f(n,m)?n)⊕n,...
HDUACM2010版13二分匹配及其应用.ppt
搜索 dfs 解题代码 hdu1241