ZOJ Problem Set - 3156 Taxi
Chieh
posted @ 2015年7月21日 15:19
in ZOJ
, 289 阅读
飞机票:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3127
题意:给你n个人n<=100,m辆车,n<=m<=100,然后给你n+m个坐标代表人和车的位置,最后再给你个速度v,求出最少的时间,使得每个人都有一辆车。(其中每个人都是同步进行的)
分析:这种题的话,就是相当于把n个人匹配到m辆车的n辆中,可以用二分图匹配算法,匈牙利的话是O(VE)那怎么求这个最少时间呢,其实可以二分求,然后每次二分的时间t,我们可以用O(nm)的时间,求的用t的时间,n个人可以和m辆车的哪几辆匹配,然后建图,跑一边匈牙利,如果可以最大匹配的话,那么这个时间是ok的,那么我们把上限变为t-0.001,因为要保留两位小数,反之把下限变为t+0.001,继续二分,最后输出答案即可。复杂的为logT*(n*m+VE),还是ok的,因为n和m比较小,最后啪啪啪就可以AC了
/* Author:Chieh Because Of Coding */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <map> #include <stack> #define LL long long #define INF 1e9 #define EPS 1e-9 using namespace std; const int maxn=123; struct he { double x,y; } Sky[2][maxn]; int n,m; double ai[maxn][maxn]; double l,r; double calT(int i,int j,double v) { double dis=sqrt((Sky[0][i].x-Sky[1][j].x)*(Sky[0][i].x-Sky[1][j].x)+(Sky[0][i].y-Sky[1][j].y)*(Sky[0][i].y-Sky[1][j].y)); return dis/v; } void init() { for(int i=1; i<=n; i++)scanf("%lf%lf",&Sky[0][i].x,&Sky[0][i].y); for(int i=1; i<=m; i++)scanf("%lf%lf",&Sky[1][i].x,&Sky[1][i].y); double v; scanf("%lf",&v); for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { ai[i][j]=calT(i,j,v); } } r=2000000.0/v; } bool bi[maxn][maxn]; int Link[maxn]; bool vis[maxn]; bool DFS(int now) { for(int i=1; i<=m; i++) { if(bi[now][i]&&!vis[i]) { vis[i]=1; if(Link[i]==0||DFS(Link[i])) { Link[i]=now; return true; } } } return false; } void play() { double MIN=r; l=0; while(l<=r) { double mid=(l+r)/2; memset(bi,0,sizeof(bi)); for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { if(ai[i][j]<=mid)bi[i][j]=1; } } memset(Link,0,sizeof(Link)); bool flag=1; for(int i=1; i<=n; i++) { memset(vis,0,sizeof(vis)); if(DFS(i))continue; flag=0; break; } if(flag) { MIN=min(MIN,mid); r=mid-0.001; } else { l=mid+0.001; } } printf("%.2f\n",MIN); } int main() { while(scanf("%d%d",&n,&m)!=EOF) { init(); play(); } // cout << "Hello world!" << endl; return 0; }