uva 10122 Mysterious Mountain and ZOJ 1231 Mysterious Mountain (二分+二部图最大匹配)



 Problem F. Mysterious Mountain 

The Problem

A group of M people is chasing a very strange animal. They believe that it will stay on a myterious mountain T, so they decided to climb on it and have a loot. The mountain looks ordinary, shown below:

That is, the outline of the moutain consists of N+1 segments. The endpoints of them are numbered 0..N+1 from left to right. That is to say, x[i] < x[i+1] for all 0<=i<=n. And also, y[0]=y[n+1]=0, 1<=y[i]<=1000 for all 1<=y<=n.

According to their experience, the animal is most likely to stay at one of the N endpoits numbered 1..N . And... funny enough, they soon discover that M=N, so each of them can choose a different endpoint to seek for the animal.

Initially, they are all at the foot of the mountain. (i.e at (si,0) ) For every person i, he is planing to go left/right to some place (x,0) (where x is an integer - they do not want to take time to work out an accurate place) at the speed of wi, then climb directly to the destination along a straight line(obviously, no part of the path that he follows can be OVER the mountain - they can't fly) at the speed of ci. They don't want to miss it this time, so the teamleader wants the latest person to be as early as possible. How fast can this be done?

The Input

The input will contain no more than 10 test cases. Each test case begins with a line containing a single integer N(1<=N<=100). In the following N+2 lines, each line contains two integers xi and yi(0<=xi,yi<=1000) indicating the coordinate of the ith endpoints. in the following N lines, each line contains three intergers ci,wi and si describing a person(1<=ci < wi<=100, 0<=si<=1000) - the climbing speed, walking speed and initial position. The test case containing N=0 will terminate the input and should not be regarded as a test case.

The Output

For each test case, output a single line containing the least time that these people must take to complete the mission, print the answer with two decimal places.

Sample Input

3
0 0
3 4
6 1
12 6
16 0
2 4 4
8 10 15
4 25 14
0

Sample Output

1.43

Note

In this example, Person 1 goes to (5,0) and climbs to endpoint 2, Person 2 climbs directly to endpoint 3. person 3 goes to (4,0) and climbs to endpoint 1. Shown below:



题目大意:

首先一个(表示 个人,n个山顶) 接下来 n+2 行分别描述 这个山(按 排序的,依次是 起点坐标,n个山顶坐标,重点坐标),接下来n行是n个人的描述,每个人的步行速度,以及 爬山速度,以及起始 位置,因为一开始都在山脚下,每个人选择一个山去爬,使得最后一个人爬上山的时间最少? 每个人爬山是 左右移动到一个整数点位置,然后直接爬往山顶。

 

解题思路:

首先求一下每个人到每座山峰的最少时间,这个计算有点坑。WA了好多次,因为是整数点,可以在有效范围内枚举整数点。

然后是 用二分枚举最终答案 ,如果某个人到达某个山顶时间小于 t,则将整个人与这个山峰连一条边,最终形成的图能够最大匹配为n,也就是每个人都能爬一座山,就行了。

所以这题知识点是:二分+二部图最大匹配

 

解题代码:


#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <algorithm>
using namespace std;

const int maxn=110;
int path[maxn][maxn],visited[maxn],link[maxn];
int n,m;
double a[maxn][maxn];

struct point{
    int x,y;
    point(int x0=0,int y0=0){
        x=x0;y=y0;
    }
}p[maxn];

struct line{
    point p1,p2;
    line(point p10,point p20){
        p1=p10;
        p2=p20;
    }
};


void initial(){
    memset(link,-1,sizeof(link));
    memset(path,0,sizeof(path));
}

double getvalue(int l,int r,point p0,int x,int vc,int vw){
    double ans=1e9;
    for(int t=l;t<=r;t++){
        double tmp=abs(x-t)*1.0/(vw*1.0) + sqrt( (t-p0.x)*(t-p0.x) + p0.y*p0.y )/(vc*1.0);
        if(tmp<ans) ans=tmp;
    }
    return ans;
}

void input(){
    m=n;
    for(int i=0;i<=n+1;i++){
        scanf("%d%d",&p[i].x,&p[i].y);
    }
    int vc,vw,x,l,r;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&vc,&vw,&x);
        for(int j=1;j<=n;j++){
            if(x<p[j].x){
                l=x;
                for(int t=0;t<j;t++){
                    if(p[t].y<p[j].y-1e-6){
                        double lx=1.0*(p[t].x*p[j].y-p[j].x*p[t].y)/(p[j].y-p[t].y);
                        if( int(lx-1e-5)+1>l ) l=int(lx-1e-5)+1;
                    }
                }
                a[j][i]=getvalue(l,p[j].x,p[j],x,vc,vw);
            }else{
                r=x;
                for(int t=j+1;t<=n+1;t++){
                    if(p[t].y<p[j].y-1e-6){
                        double rx=1.0*(p[t].x*p[j].y-p[j].x*p[t].y)/(p[j].y-p[t].y);
                        if( int(rx+1e-5)<r ) r=int(rx+1e-5);
                    }
                }
                a[j][i]=getvalue(p[j].x,r,p[j],x,vc,vw);
            }
        }
    }
}

int can(int x){
    for(int i=1;i<=m;i++){
        if(visited[i]==-1 && path[x][i]>0){
            visited[i]=1;
            if( link[i]==-1 || can(link[i]) ){
                link[i]=x;
                return 1;
            }
        }
    }
    return 0;
}

int getBip(double c){
    int ans=0;
    initial();
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(a[i][j]<=c) path[i][j]=1;
        }
    }
    for(int i=1;i<=n;i++){
        memset(visited,-1,sizeof(visited));
        if(can(i)) ans++;
    }
    return ans;
}


void solve(){
    double l=0,r=4000;
    while(r-l>1e-7){
        double mid=(l+r)/2.0;
        if(getBip(mid)>=n) r=mid;
        else l=mid;
    }
    printf("%.2lf\n",(l+r)/2.0);
}

int main(){
    while(scanf("%d",&n)!=EOF && n!=0){
        input();
        solve();
    }
    return 0;
}

posted @ 2014-04-12 10:07  炒饭君  阅读(168)  评论(0编辑  收藏  举报