[codeforces 852 D] Exploration Plan 解题报告 (二分+最大匹配)
题目链接:http://codeforces.com/problemset/problem/852/D
题目大意:
有V个点,N个队伍,E条边,经过每条边有个时间,告诉你初始N个队伍的位置,求至少有K个队伍在不同的点的最短时间
题解:
我们二分答案时间,显然具有单调性。先floyd预处理两点之间的最短路,二分答案后把每个人和他可以走到的点连起来,跑一次最大匹配。若最大匹配数大于等于k,说明当前答案小了,否则大了
(每个匹配相等于一个人和他最终去的位置)
#include<algorithm> #include<cstring> #include<iostream> #include<cstdio> using namespace std; const int N=600+15; const int inf=1e9+7; const int Inf=1731311; int v,e,n,k; int pos[N],d[N][N],mp[N][N],match[N],vis[N]; inline int read() { char ch=getchar(); int s=0,f=1; while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();} return s*f; } void floyd() { for (int k=1;k<=v;k++) for (int i=1;i<=v;i++) for (int j=1;j<=v;j++) d[i][j]=min(d[i][j],d[i][k]+d[k][j]); } bool dfs(int x) { for (int i=1;i<=v;i++) { if (vis[i]||!mp[x][i]) continue; vis[i]=1; if (match[i]==-1||dfs(match[i])) { match[i]=x; return true; } } return false; } int check(int l) { memset(match,-1,sizeof(match)); for (int i=1;i<=n;i++) for (int j=1;j<=v;j++) mp[i][j]=(d[pos[i]][j]<=l); int ans=0; for (int i=1;i<=n;i++) { memset(vis,0,sizeof(vis)); if (dfs(i)) ans++; } return ans; } int main() { v=read();e=read();n=read();k=read(); for (int i=1;i<=v;i++) for (int j=1;j<=v;j++) if (i!=j) d[i][j]=inf; for (int i=1;i<=n;i++) pos[i]=read(); for (int i=1,u,v,w;i<=e;i++) { u=read();v=read();w=read(); d[u][v]=d[v][u]=min(d[u][v],w); } floyd(); int l=0,r=Inf,ans=Inf; while (l<r) { int mid=l+r>>1; if (check(mid)>=k) r=mid,ans=min(ans,r); else l=mid+1; } if (ans==Inf) puts("-1"); else printf("%d\n",ans); return 0; }
星星之火,终将成燎原之势