• POJ 3714 Raid


    题目:

    D - Raid
    Time Limit:5000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u

    Description

    After successive failures in the battles against the Union, the Empire retreated to its last stronghold. Depending on its powerful defense system, the Empire repelled the six waves of Union's attack. After several sleepless nights of thinking, Arthur, General of the Union, noticed that the only weakness of the defense system was its energy supply. The system was charged by N nuclear power stations and breaking down any of them would disable the system.

    The general soon started a raid to the stations by N special agents who were paradroped into the stronghold. Unfortunately they failed to land at the expected positions due to the attack by the Empire Air Force. As an experienced general, Arthur soon realized that he needed to rearrange the plan. The first thing he wants to know now is that which agent is the nearest to any power station. Could you, the chief officer, help the general to calculate the minimum distance between an agent and a station?

    Input

    The first line is a integer T representing the number of test cases.
    Each test case begins with an integer N (1 ≤ N ≤ 100000).
    The next N lines describe the positions of the stations. Each line consists of two integers X (0 ≤ X ≤ 1000000000) and Y (0 ≤ Y ≤ 1000000000) indicating the positions of the station.
    The next following N lines describe the positions of the agents. Each line consists of two integers X (0 ≤ X ≤ 1000000000) and Y (0 ≤ Y ≤ 1000000000) indicating the positions of the agent.  

    Output

    For each test case output the minimum distance with precision of three decimal placed in a separate line.

    Sample Input

    2
    4
    0 0
    0 1
    1 0
    1 1
    2 2
    2 3
    3 2
    3 3
    4
    0 0
    0 0
    0 0
    0 0
    0 0
    0 0
    0 0
    0 0

    Sample Output

    1.414
    0.000



    *********************************************

    题目大意是:两个坐标集,求两个坐标集之间最短的点距。
    先放上一个我自己写的,绝对超时也真的超时的代码:
     1 #include<stdio.h>
     2 #include<math.h>
     3 #define maxn 10000500000
     4 double  dis(int a,int b,int x,int y)
     5 {
     6     return sqrt((a-x)*(a-x)+(b-y)*(b-y));
     7 }
     8 int main()
     9 {
    10     int T,n,a[100500],b[100500],x[100500],y[100500],i,j;
    11     double minn,p;
    12     scanf("%d",&T);
    13     while(T--)
    14     {
    15         minn=maxn;
    16         scanf("%d",&n);
    17         for(i=0;i<n;i++)
    18             scanf("%d%d",&a[i],&b[i]);
    19         for(i=0;i<n;i++)
    20             scanf("%d%d",&x[i],&y[i]);
    21         for(i=0;i<n;i++)
    22             for(j=0;j<n;j++)
    23             {
    24                 p=dis(a[i],b[i],x[j],y[j]);
    25                 if(p<minn)
    26                     minn=p;
    27                 if(minn==0)
    28                     break;
    29             }
    30         printf("%.3lf
    ",minn);
    31     }
    32     return 0;
    33 }
    View Code

    再就是一学姐的代码,虽然过了,但是都觉得是水过去的,数据太弱了,这都水过了Orz......1469MS

     1 #include<math.h>
     2 #include<stdio.h>
     3 #include<algorithm>
     4 #include<iostream>
     5 using namespace std;
     6 class  A
     7 {
     8 public:
     9     double  x;
    10     double  y;
    11     int biao;
    12 }a[22000000];
    13 double dis(double a,double  b,double  c,double  d)
    14 {
    15     return sqrt((c-a)*(c-a)+(d-b)*(d-b));
    16 }
    17 bool cmp(A a,A b)
    18 {
    19     return ((a.x<b.x) || (a.x==b.x&&a.y<b.y));
    20 }
    21 int main()
    22 {
    23     int T;
    24     scanf("%d",&T);
    25     while(T--)
    26     {
    27         double  minn=1000000000000,t;
    28         int n,i;
    29         scanf("%d",&n);
    30         for(i=0;i<n;i++)
    31         {
    32             scanf("%lf%lf",&a[i].x,&a[i].y);
    33             a[i].biao=1;
    34         }
    35         for(i=n;i<2*n;i++)
    36         {
    37             scanf("%lf%lf",&a[i].x,&a[i].y);
    38             a[i].biao=0;
    39         }
    40         sort(a,a+2*n,cmp);
    41         for(i=0;i<n*2-1;i++)
    42             if(a[i].biao!=a[i+1].biao)
    43         {
    44             t=dis(a[i].x,a[i].y,a[i+1].x,a[i+1].y);
    45             if(t<minn)
    46                 minn=t;
    47         }
    48         printf("%.3lf
    ",minn);
    49     }
    50     return 0;
    51 }
    View Code
    其实我那个代码稍优化下就不会超时,剪枝下,接下来是暴力+剪枝法 1500MS
    #include<math.h>
    #include<stdio.h>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    class  A
    {
    public:
        double  x;
        double  y;
        int biao;
    }a[22000000];
    double dis(double a,double  b,double  c,double  d)
    {
        return sqrt((c-a)*(c-a)+(d-b)*(d-b));  //距离
    }
    bool cmp(A a,A b)
    {
        return ((a.x<b.x) || (a.x==b.x&&a.y<b.y));  
    }
    int main()
    {
        int T,j;
        scanf("%d",&T);
        while(T--)
        {
            double  minn=1000000000000,t;
            int n,i;
            scanf("%d",&n);
            for(i=0;i<n;i++)
            {
                scanf("%lf%lf",&a[i].x,&a[i].y);
                a[i].biao=1;
            }
            for(i=n;i<2*n;i++)
            {
                scanf("%lf%lf",&a[i].x,&a[i].y);
                a[i].biao=0;
            }
            sort(a,a+2*n,cmp);   //按x排序
            for(i=0;i<n*2-1;i++)
                for(j=i+1;j<2*n;j++)
            { 
                if(a[i].biao==a[j].biao)  continue; //是铜一个坐标集里的
                if(a[j].x-a[i].x>=minn)    //这是已经不是最短距离了,跳出
                    break;
                t=dis(a[i].x,a[i].y,a[j].x,a[j].y);
                if(minn>t)
                    minn=t;
            }
            printf("%.3lf
    ",minn);
        }
        return 0;
    }
    
    
    再就是分治法+剪枝优化:
    来自学姐:http://blog.csdn.net/cfreezhan/article/details/9452403
      1 /****************************************************************
      2 D    Accepted    4896 KB    1704 ms    C++    1678 B    2013-07-24 15:47:05
      3 算法:分治法 + 剪枝
      4 题意:给一个点集A,一个点集B,
      5       求min(distance(x, y))(x∈A,y∈B)
      6 思路:把两个集合中的点弄在一个数组中排序 
      7       排序方法:x 坐标从左到右, y坐标从下到上(PS: y左边也可以不排序)
      8        
      9       剪枝优化:p[j].x-p[i].x >= mini,则 break
     10                  因为如果是这种情况,那么加上 y 坐标上的就一定会 > mini
     11                  直接跳出这一点,遍历下一点即可。
     12       分治法:先把问题分解成左右两个子问题递归求解,然后再合并即可【一般是分成相等的两半效率最高了】
     13               对于此问题:
     14               先分成:从左边到中间 和 从中间到右边这两个子问题求出一个可能的最小距离
     15                       然后再合并:从左边(左边到中间的那段)取出一个点 u,
     16                                    从右边取出一个点 v
     17                                    找出最小的dist(u,v)与前面的子问题中求出的最小距离比较即可
     18 **********************************************************************/
     19 #include<stdio.h>
     20 #include<math.h>
     21 #include<string.h>
     22 #include<algorithm>
     23 using namespace std;
     24 
     25 const int maxn =  100000+10;
     26 const double INF = 1000000000*2;
     27 
     28 struct Point{
     29     double x,y;
     30     int flag;
     31 }p[2*maxn];
     32 int index[2*maxn];
     33 
     34 bool cmp(Point a, Point b)
     35 {
     36     return a.x < b.x;
     37 }
     38 
     39 double dist(Point a, Point b)
     40 {
     41     if(a.flag != b.flag)
     42         return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
     43     else return INF; /** 两点属于同一集合 */
     44 }
     45 
     46 double min_dist(int left, int right) /**[left, right) 左闭右开区间 */
     47 {
     48     if(right - left == 1) return INF; /** one point 只有一个点 */
     49     if(right - left == 2) return dist(p[right],p[right+1]); /** two point 正好两个点 */
     50 
     51     int mid = left+(right-left)/2; /** 分治法第一步:划分成[left, mid)和[mid, right) */
     52 
     53     double Min = min(min_dist(left, mid), min_dist(mid, right)); /** 分治法第二步:递归求解 */
     54 
     55     int L = 0; /**记录每次合并找的点数*/
     56     /**向左向右分别找时记得剪枝优化否则还是会 TLE **/
     57     for(int i = mid-1; i >= left && p[mid-1].x-p[i].x < Min; i--)
     58     { /** 分治法第三步:合并(1) --- 从分界点开始往左找到可能的点的最左边下标边界 */
     59         index[L++] = i;
     60     }
     61     int Mid_Index = L; /** 记录往左找时, 第一个点的下标 */
     62     for(int i = mid; i < right && p[i].x-p[mid-1].x < Min; i++)
     63     { /** 分治法第三步:合右边并(2) --- 从分界点开始往右找到可能的点的最右边的下标边界*/
     64         index[L++] = i;
     65     }
     66 
     67     double distance = INF;
     68     for(int i = 0; i < Mid_Index; i++) /** 遍历往左找的点*/
     69     {/** 分治法第三步:正式合并(3) --- dist(从左边选择的点, 从右边选择的点)*/
     70         for(int j = Mid_Index; j < L; j++) /** 遍历往右找的点*/
     71         {
     72             Min = min(Min, dist(p[index[i]], p[index[j]])); /** 更新最短距离*/
     73         }
     74     }
     75     return Min;
     76 }
     77 
     78 int main()
     79 {
     80     int T;
     81     int n,N;
     82     scanf("%d", &T);
     83     while(T--)
     84     {
     85         scanf("%d", &n);
     86         N = 2*n;
     87         for(int i = 0; i < n; i++)
     88         {
     89             scanf("%lf%lf", &p[i].x, &p[i].y);
     90             p[i].flag = 0;
     91         }
     92         for(int i = n; i < N; i++)
     93         {
     94             scanf("%lf%lf", &p[i].x, &p[i].y);
     95             p[i].flag = 1;
     96         }
     97         sort(p,p+N,cmp);
     98 
     99         double  ans = min_dist(0, N);
    100         printf("%.3lf
    ", ans);
    101     }
    102     return 0;
    103 }
    
    
    过一阵再来看看分治法。

  • 相关阅读:
    复习时间
    核反应堆
    假期编程
    剪花布条
    Atcoder Regular Contest 072 C Alice in linear land(思维题)
    xss攻击入门
    转发 DDoS攻防战 (一) : 概述
    XSS跨站脚本攻击
    sql注入
    关于阿里云图片识别接口的demo
  • 原文地址:https://www.cnblogs.com/riddle/p/3220110.html
Copyright © 2020-2023  润新知