POJ 3714 Raid

//POJ 3714 Raid
//AC by warteac
//2013-7-19
/*
    法一:先排序,然後依次向後找最小距離,並且剪枝
         重點是,不需要指定找 人到站點或是站點到人的距離,把所有的都看成點,就找兩點最短距離即可
         爲了區別用flag標記,求距離時判斷flag是否相同。
    6764K 3579MS C++ 2090B 2013-07-19 11:44:37 
    法二:二分是高效算法;
         重點是,合併的時候,求最短距離橫跨左右兩邊的情況,有一個剪枝的動作,不加依然會超時,詳見代碼
         TLE: 重複調用函數導致超時,不是算法的問題,詳見代碼
    6768K 2922MS C++ 2725B 2013-07-19 11:46:29 
*/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include <iomanip> 
#include<algorithm>
using namespace std;

const double eps = 1e-5;
const double MAXLEN = 1000000000.0;
struct posi{
    double x;
    double y;
    bool flag;   //0 is agent,1 is raid
};

vector <posi> p;
int num;
double min_length;

double length(posi p1, posi p2){
    if(p1.flag != p2.flag)
    return sqrt((p2.x - p1.x)*(p2.x - p1.x)+(p2.y - p1.y)*(p2.y - p1.y));
    else return MAXLEN;
}
bool cmp(posi p1, posi p2){
    if(fabs(p1.x - p2.x) < eps){
        return p1.y < p2.y;
    }else{
        return p1.x < p2.x;
    }
}
//////////////////法一/////////////////////////////////
/*double getMinLength(int i){
    double min = MAXLEN;
    for(int j = i+1; j < 2*num; j++){
        if(p[i].flag != p[j].flag){
             double temp = length(p[i],p[j]);
        if(temp - min < eps){
            min = temp;
        }
        else if(fabs(p[i].x - p[j].x) > min)//如果不加這句if(),有BUG,但POJ沒有檢查出來,具體測試數據見下面
                break;
        }
    }
    return min;
}*/
////////////////////法一結束/////////////////////////////

////////////////////法二////////////////////////////////
double getMinLength(int x, int y){
    if(y - x <= 2){
        double len,minlen = MAXLEN;
        for(int i = x; i < y; i++)
            for(int j = x+1; j < y; j++){
                len = length(p[i],p[j]);
                //minlen <?= len;
                if(len < minlen) minlen = len;
            }
    return minlen;
    }else{
        double r,result = MAXLEN;
        int i,j;
        int m = (x + y) / 2;//第一步:劃分
        //result = getMinLength(x,m) < getMinLength(m,y) ? getMinLength(x,m) : getMinLength(m,y);//第二步:遞歸解決子問題
        //TLE: 上式中調用getMinLength()四次,在遞歸次數龐大時就會導致超時了
        //解決辦法,用兩個變量Llen,Rlen 保存函數的調用值
        double Llen,Rlen;
        Llen = getMinLength(x,m);
        Rlen = getMinLength(m,y);
        result = Llen < Rlen ? Llen : Rlen;//第二步:遞歸解決子問題
        for(i = m-1; i >= x; i--){//第三步:合併
            if(fabs(p[m].x - p[i].x) > result) break;//剪枝
            for(j = m; j < y; j++){
                if(fabs(p[m].x - p[j].x) > result) break;//剪枝
                r = length(p[i],p[j]);
                //result <?= r;
                if(result > r) result = r;
            }
        } 
       return result;
    }
}
/////////////////////法二結束///////////////////////////////

int main(){
    int n,i,j;
    cin >> n;
    while(n--){
        posi t;
        cin >> num;
        p.clear();
        min_length = MAXLEN;
        for(i = 0; i < num; i++){
            cin >> t.x >> t.y;
            t.flag = 0;//agent
            p.push_back(t);
        }
        for(i = 0; i < num; i++){
            cin >> t.x >> t.y;
            t.flag = 1;//raid
            p.push_back(t);
        }
        sort(p.begin(),p.end(),cmp);
        
        //////////////////法一///////////////////////////
        /* for(int k = 0 ;k < p.size();k++){
        }
        for(j = 0; j < 2*num-1; j++){
            double mlen = getMinLength(j);
            if(mlen < min_length) min_length = mlen;
        }*/
        //////////////////法一結束/////////////////////////////
        
        //////////////////法二//////////////////////////////
        min_length = getMinLength(0,p.size());
        //////////////////法二結束//////////////////////////
        
        cout <<setiosflags(ios::fixed);  
        cout << setprecision(3);
        cout << min_length << endl;
    }
    return 0;
}

/*
測試BUG的數據
INPUT:
1
3
0 0
13 13
15 15
2 5
4 0
4 -6
OUTPUT:(right)
4.000
OUTPUT:(wrong)
5.385    
*/


 

發佈了55 篇原創文章 · 獲贊 8 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章