1. 程式人生 > >swust oj凸包面積(0249)_分治法

swust oj凸包面積(0249)_分治法

本文目錄:oj題目 -> 分治法思路 -> 具體過程 -> tips -> 測試資料 -> 程式碼

這道題本身不是很難喲,不要被嚇到,然後就可以開始做了O(∩_∩)O~~

題目


分治法思路:見http://download.csdn.net/download/xiao_huang2013/7414317

先預排序,預排序後最左和最右的點肯定是凸包中的點。然後可以遞迴的從內向外擴充套件凸包,在當前直線的2側尋找最高點,
最高點肯定在凸包中,這裡涉及到一些數學知識:

a,首先定義射線p1到p2的左側:若p1 p2  p構成的順序是逆時針,稱p在射線的左側

b,三角形p1  p2   p3的面積等於下列行列式的一半:
僅當p3在射線p1p2左側時這個值才為正。

由此我們很容易求p1,p2左側的最高點(離直線最遠的點,這個點即凸包向外擴充套件得到的新頂點),得到一個最高點後,就得到了2條新邊,繼續向外擴充套件

那麼寫這個題的過程便可以是:

1.寫主函式,輸入

2.calSize函式,以最左右的兩點為引數(令為p1,p2)

3.編寫calSize函式,作用是呼叫calLSize、calRSize函式,分別用來求p1p2直線上下的面積

4.編寫calLsize、calRSize函式

5.寫calLsize時,判斷方向,排除已經用掉的點,找到當前p點,根據求面積公式寫函式求△pp1p2面積,替換頂點遞迴

5.定義p1->p2->p[i]逆時針為左,反之為右,因為剛好判斷順逆時針的叉乘結果的絕對值等於三角形面積的兩倍,於是共用calArea(求面積)函式

tips:

判斷兩個平面向量構成的方向是順時針還是逆時針:

a = (ax,ay) , b = (bx,by)

a X b = ax * by  - ay *bx

a X b > 0則是逆時針,< 0 則是順時針

已知三點座標求圍成三角形的面積(也是用叉乘,所以我寫在同一個函式裡的,一起用):

ax = x1 - x2; ay = y1 - y2; bx = x2 - x3; by = y2 - y3;

a X b = ax * by  - ay *bx

s = 0.5 * fabs((double)(a X b));//fabs為取絕對值,需要加上#include<math.h>

錯誤提示:XX函式找不到識別符號

改正:寫函式時如果呼叫在先定義在後,需要先宣告,再呼叫(宣告 != 呼叫)

錯誤提示:有多個過載函式XX例項與引數列表匹配

改正:看是否符合公式使用條件,如fabs只用於浮點數

測試資料:(不包括資料組數T)

//正方形中間的點
5
0 0
2 0
0 2
2 2
1 1

//多組,記得初始化used[]
5
0 0
1 0
0 1
1 2
2 1

//比較的時候寫成if (x[j] > maxX)maxX = j;應該是x[j] > x[maxX],min也寫錯了
10
0 0
10 10
0 10
10 0
3 5
6 3
4 8
8 3
9 1
9 9

10
0 0
10 10
10 0
0 10
5 5
4 8
5 0
10 5
1 8
6 2

//答案0.0    1.0     0.5      6.0
4
1
184 225
4
0 0
0 1
1 0
1 1
3
0 0
0 1
1 0
6
0 2
1 1
0 0
2 1
3 0
3 2

程式碼:

#include<stdio.h>//分治法
#include<iostream>
using namespace std;
#include<math.h>
 
int x[110],y[110],used[110]={0};
double size;
 
double TriangelSize(int i,int j,int k)
{
    int x1=x[i],x2=x[j],x3=x[k],y1=y[i],y2=y[j],y3=y[k];
    used[i] = used[j] = used[k] = 1;
    return 0.5*fabs( (double)(x2-x1)*(y3-y2)-(y2-y1)*(x3-x2) );
}
 
//定義:使得原兩點與新的點連線方向為逆時針的,為LSide,即左,calArea>0則逆,<則順
double calArea(int p1,int p2,int i)
{
    int x1=x[p1],y1=y[p1],x2=x[p2],y2=y[p2],x3=x[i],y3=y[i];
    return 0.5*((x2-x1)*(y3-y2)-(x3-x2)*(y2-y1));
}
 
void calLSize(int n,int p1,int p2)
{
    int p=-1;
    double sizeMax=-1;
    for (int i = 0; i < n; i++)
    {
        if (used[i] == 1 || calArea(p1,p2,i) <= 0 || i == p1 || i == p2)continue;//不符合構成新三角形的條件的點
        if (calArea(p1,p2,i) > sizeMax)
        {
            sizeMax = calArea(p1,p2,i);
            p = i;
        }
    }
    if (p == -1)return;
 
    size += TriangelSize(p1,p2,p);
    calLSize(n,p1,p);
    calLSize(n,p,p2);
}
 
void calRSize(int n,int p1,int p2)
{
    int p=-1;
    double sizeMax=-1;
    for (int i = 0; i < n; i++)
    {
        if (used[i] == 1 || calArea(p1,p2,i) >= 0 || i == p1 || i == p2)continue;//不符合構成新三角形的條件的點
        if (-calArea(p1,p2,i) > sizeMax)
        {
            sizeMax = -calArea(p1,p2,i);
            p = i;
        }
    }
    if (p == -1)return;
    size += TriangelSize(p1,p2,p);
    calRSize(n,p1,p);
    calRSize(n,p,p2);
}
 
void calSize(int n,int p1,int p2)
{
    calLSize(n,p1,p2);
    calRSize(n,p1,p2);
}
 
int main()
{
    int T,n,i,j,minX,maxX;
    cin>>T;
    for(i = 0; i < T; i++)
    {
        size = 0;
        cin>>n;
        for(j = 0; j < n; j++)
        {
            cin>>x[j]>>y[j];
            used[j] = 0;
        }
        minX = maxX = x[0];
        for(j = 0; j < n; j++)
        {
            if (x[j] > x[maxX])maxX = j;
            if (x[j] < x[minX])minX = j;
        }
        calSize(n,minX,maxX);
        printf("%.1lf\n",size);
    }
    return 0;
}

本文地址:http://blog.csdn.net/qq_33810513/article/details/51440320

written by Sneexy

o(≧v≦)o~~AC了好興奮