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;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

炒饭君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值