zoukankan      html  css  js  c++  java
  • R的农场 chebnear

       评测传送门

    Description
    最近,R 终于获得了一片他梦寐以求的农场,但如此大的一片农场,想要做好防卫工作可不是一件容易的事。所以 R 购买了 N 个守卫,分别让他们站在一定的位置上(守卫不可移动,同一位置上至多有一个守卫)。但是,安排了所有的守卫之后,R 才发现,守卫们彼此十分厌恶。经 R 研究,当某两个守卫距离≤K,他们就会发生争吵;但是,想要守卫们和解也是不难的——只需要 R 给出的平均工资能使两人满意,他们就会同意和解、成为朋友;当然,如果两个守卫有共同的朋友,他们也会和解成为朋友。R 非常不想守卫们争吵,因此他想找出,在能使所有守卫闭嘴的前提下,平均工资的最小值是多少。

    他想到了一个绝妙的方法,但他忙着去 Farm,没时间,所以这个任务就交给你了。
    Input
    第 1 行为三个数 N, M, K。
    接下来 N 行为 N 个守卫的位置,每行包含两个实数 x, y (x≥0, y≥0)。
    接下来 M 行,每行三个数,u, v, w,代表若平均工资≥w,则 u 和 v 同意和解。
    Output
    输出文件有且仅有一行,一个实数 p,代表最小的平均工资。

    data range

    M≤100000, M≤200000

    Attention
    1、本题中的距离定义:对于两个守卫 (x1, y1), (x2, y2) ,它们的距离定义为 max{|x1-x2|,|y1-y2|} 。
    2、整数均在 int 范围内,实数均在 double 范围内。
    3、给定图中可能存在重边。
    4、输出结果保留三位小数。

    25分思路:

      预处理出发生冲突的守卫编号

      然后依据输入的两个守卫成为friends的最低平均工资连边

      边权即为输入的最低工资

      然后枚举之前预处理出的发生冲突的守卫 求出它们之间的最短路

      这里路长的定义为:经过的所有路径的边权的最大值,而不是所有路径边权相加

      在所有的最短路之间取max即可

     

    正解思路:

      枚举最低平均工资

      发现它可以二分 即若当前最低平均工资满足所有守卫无冲突

      则 r=mid-1寻找更小的 反之....

      二分工资之后怎么判断是否符合题意呢:

      若两个守卫成为朋友的最低工资<=mid 那么连边(用并查集就可以了)

      然后求平面内最近点对(连了线的两点不对答案做贡献)   (这里是最近点对qwq)

      若最近点对之间的距离>k则合题意

    我觉得上面辣种求最近点对的思路很好但是我调了很久的code还没好

    然后又借鉴了一下wch的想法   我发现也很好啊不用求最近点对了

    也是分治 找有没有两点之间的距离小于等于k 直接在solve里面判断

    CODE:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cmath>
     5 #define R register
     6 #define go(i,a,b) for(R int i=a;i<=b;i++)
     7 #define M 100001
     8 #define db double
     9 #define inf 210000000.0
    10 using namespace std;
    11 struct node1{db x,y;int id;}a[M],c[M];
    12 struct node2{int u,v;db w;}b[M<<1];
    13 int n,m,f[M];
    14 db k;
    15 int find(int x){if(f[x]==x)return x;return f[x]=find(f[x]);}
    16 bool cmp1(node2 x,node2 y){return x.w<y.w;}
    17 bool cmp2(node1 x,node1 y){return x.y<y.y;}
    18 bool cmp3(node1 x,node1 y){return x.x<y.x;}
    19 bool sol(int l,int r)
    20 {
    21     if(l>=r) return 1;//边界
    22     int mid=(l+r)>>1,ct=0;
    23     if(!sol(l,mid)||!sol(mid+1,r)) return 0;
    24     while(a[l].x+k<a[mid].x) l++;
    25     while(a[r].x-k>a[mid].x) r--;
    26     go(i,l,r) c[++ct]=a[i];
    27     sort(c+1,c+ct+1,cmp2);
    28     go(i,1,ct)
    29         go(j,i+1,ct)
    30     {
    31         if(c[j].y-c[i].y>k) break;
    32         if(fabs(c[i].x-c[j].x)<=k&&find(c[i].id)!=find(c[j].id)) return 0;
    33         //这里只要判断x 因为已经保证 c[j].y-c[i].y<=k
    34     }
    35     return 1;
    36 }
    37 bool ck(int mid)
    38 {
    39     go(i,1,n) f[i]=i; //不要落掉这一步啦 写并查集的时候一定要记得!
    40     go(i,1,m)
    41     {
    42         if(b[i].w>b[mid].w) break;
    43         f[find(b[i].u)]=find(b[i].v);//注意这里啊 开始写错了找了好久qwq
    44     }
    45     return sol(1,n);
    46 }
    47 int main()
    48 {
    49     cin>>n>>m>>k;
    50     go(i,1,n) cin>>a[i].x>>a[i].y,a[i].id=i;
    51     sort(a+1,a+n+1,cmp3);//按x排序
    52     go(i,1,m) cin>>b[i].u>>b[i].v>>b[i].w;
    53     sort(b+1,b+m+1,cmp1);//按w排序
    54     //好像很少写对过二分??初始化 mid+-1什么的总是搞错
    55     //然后这题的二分还不清楚为什么我之前写的不对 要去问一下 然后再写到这里来
    56     int l=0,r=m-1,mid;//这里要注意l,r的初始化
    57     while(l<=r)
    58     {
    59         mid=(l+r)>>1;
    60         if(ck(mid)) {r=mid-1;}
    61         else l=mid+1;
    62     }
    63     printf("%.3lf",b[l].w);
    64     return 0;
    65 }
    View Code
    光伴随的阴影
  • 相关阅读:
    17. Letter Combinations of a Phone Number
    16. 3Sum Closest
    15. 3Sum
    14. Longest Common Prefix
    13. Roman to Integer
    12. Integer to Roman
    11. Container With Most Water
    10. Regular Expression Matching
    9. Palindrome Number
    8. String to Integer (atoi)
  • 原文地址:https://www.cnblogs.com/forward777/p/10360057.html
Copyright © 2011-2022 走看看