卧薪尝胆,厚积薄发。
Exploration plan
Date: Tue Nov 06 10:14:16 CST 2018 In Category: NoCategory

Description:

给一个带边权的无向图,刚开始每一个人有位置,问最少多长时间所有人任意移动有人的位置多于 $k$ 个。
$1\leqslant n\leqslant 600$

Solution:

先用 $floyed$ 预处理出两两之间的距离,然后二分时间,把人能到达的位置连成一个二分图,用匈牙利算法判断最大匹配是否超过 $k$ 个即可。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
int n,m,s,w;
#define MAXN 610
int p[MAXN];
int f[MAXN][MAXN];
struct edge
{
int to,nxt;
}e[MAXN * MAXN];
int edgenum = 0;
int lin[MAXN] = {0};
void add(int a,int b)
{
e[++edgenum] = (edge){b,lin[a]};lin[a] = edgenum;
return;
}
int match[MAXN];
bool v[MAXN];
bool find(int k)
{
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(!v[e[i].to])
{
v[e[i].to] = true;
if(match[e[i].to] == -1 || find(match[e[i].to]))
{
match[e[i].to] = k;
return true;
}
}
}
return false;
}
bool check(int k)
{
memset(lin,0,sizeof(lin));
edgenum = 0;
for(int i = 1;i <= s;++i)
for(int j = 1;j <= n;++j)
if(f[p[i]][j] <= k)add(i,j);
int ans = 0;
memset(match,-1,sizeof(match));
for(int i = 1;i <= s;++i)
{
memset(v,false,sizeof(v));
if(find(i))++ans;
}
return (ans >= w);
}
int main()
{
scanf("%d%d%d%d",&n,&m,&s,&w);
for(int i = 1;i <= s;++i)scanf("%d",&p[i]);
memset(f,0x3f,sizeof(f));
for(int i = 1;i <= n;++i)f[i][i] = 0;
int a,b,c;
for(int i = 1;i <= m;++i)
{
scanf("%d%d%d",&a,&b,&c);
f[a][b] = f[b][a] = min(f[a][b],c);
}
for(int k = 1;k <= n;++k)
for(int i = 1;i <= n;++i)
for(int j = 1;j <= n;++j)
f[i][j] = min(f[i][j],f[i][k] + f[k][j]);
int l = 0,r = 100000000,mid;
while(l < r)
{
mid = ((l + r) >> 1);
if(check(mid))r = mid;
else l = mid + 1;
}
if(l != 100000000)cout << l << endl;
else puts("-1");
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡