1. 程式人生 > >p1959 遺址[NOI導刊2009普及(6)]

p1959 遺址[NOI導刊2009普及(6)]

int amp 如何判斷 lin fine reg () getch lol

題目描述--> P1959 遺址_NOI導刊2009普及(6)

普通方法分析:

因為題目要求是找最大正方形(如果是長方形更麻煩.

講真,題目不難,耗時間!

根據題目要求,我們要找的是正方形.

我們可以根據已知兩點去判斷其他兩點是否存在

然後就到了畫圖課講解法的時候.

下面所有的dely代表縱坐標差值,delx代表橫坐標差值.

(記得在輸入的時候,標記圓柱坐標.

當我們枚舉的兩個點所在直線平行於x軸或y軸的時候↓.

直線兩側均可能有正方形

(即橫坐標差值為0縱坐標差值為0的時候.)
技術分享圖片

縱坐標相同的話,加減橫坐標差值即可.

這時只需要判斷其他位置點是否存在即可.

我們的難點在於如何判斷兩個點是傾斜的情況.

容易發現一個將一個傾斜正方形圍起來之後,四個三角形是相等的. 像這樣↓
技術分享圖片

很明顯全等吧!證明過程略

然後我們需要考慮的是兩個點所在直線斜率是正還是負的問題

(親測只考慮一種情況,不能AC此題.)

求斜率的公式: k=Δy/Δx

分母不能為0!

然後我們又開始畫圖 emmm

斜率為負有兩種情況.我們可以畫圖如下↓
技術分享圖片

斜率為正.同樣有兩種情況如下↓
技術分享圖片

按照圖片去寫代碼即可.

--------------------代碼---------------------

#include<bits/stdc++.h>
#define IL inline
#define RI register int
IL void in(int &x)
{
    int f=1;x=0;char s=getchar();
    while(s>‘9‘ or s<‘0‘){if(s==‘-‘)f=-1;s=getchar();}
    while(s<=‘9‘ and s>=‘0‘){x=x*10+s-‘0‘;s=getchar();}
    x*=f;
}
int n,x[30008],y[30008];
bool res[6008][6008];
int ans;
IL int dis(int a,int b){return abs(a-b);}
IL bool ok(int x,int y)
{
    if(x<0 || y<0 || x>5000 || y>5000 || !res[x][y])return false;
    return true;
}
IL void search(int px,int py,int nx,int ny)
{
    int delx=dis(px,nx),dely=dis(py,ny);
    if(delx==0)
    {
        if(ok(px+dely,py) && ok(nx+dely,ny))
            ans=std::max(ans,dely*dely);
        else if(ok(px-dely,py) && ok(nx-dely,ny))
            ans=std::max(ans,dely*dely);
    }
    else if(dely==0)
    {
        if(ok(px,py+delx) && ok(nx,ny+delx))
             ans=std::max(ans,delx*delx);
        else if(ok(px,py-delx) && ok(nx,ny-delx))
            ans=std::max(ans,delx*delx);
    }
    else if(((ny-py)/(nx-px))<0 && nx-px!=0)
    {
        if(ok(px+dely,py-delx) && ok(nx-dely,ny-delx))
            ans=std::max(delx*delx+dely*dely,ans);
        else if(ok(px+dely,py+delx) && ok(nx+dely,ny+delx))
            ans=std::max(delx*delx+dely*dely,ans);
    }
    else if(((ny-py)/(nx-px))>0 && nx-px!=0)
    {
        if(ok(px+dely,py-delx) && ok(nx+dely,ny-delx))
            ans=std::max(delx*delx+dely*dely,ans);
        else if(ok(px-dely,py+delx) && ok(nx-dely,ny+delx))
            ans=std::max(delx*delx+dely*dely,ans);
    }
}
int main(void)
{
    in(n);
    for(RI i=1;i<=n;i++)
        in(x[i]),in(y[i]),res[x[i]][y[i]]=true;
    for(RI i=1;i<=n;i++)
        for(RI j=1;j<=n;j++)
            if(i!=j)search(x[i],y[i],x[j],y[j]);
    printf("%d",ans);
}

如果RE的話記得判邊界,還要判斷是否有標記.

可能會有些麻煩,但個人感覺較好理解.

更簡單的方法

通過我們的畫圖.(如果你不知道請向上看圖 qwq

我們很容易發現

新點的橫坐標,只與dely有關.

新點的縱坐標,只與delx有關.

無論直線如何擺放都是如此.

且對應坐標為一個加一個減.

因此我們可以精簡代碼成下面這樣:

--------------------代碼--------------------

#include<bits/stdc++.h>
#define IL inline
#define RI register int
IL void in(int &x)
{
    int f=1;x=0;char s=getchar();
    while(s>‘9‘ or s<‘0‘){if(s==‘-‘)f=-1;s=getchar();}
    while(s<=‘9‘ and s>=‘0‘){x=x*10+s-‘0‘;s=getchar();}
    x*=f;
}
int n,x[30008],y[30008];
bool res[6008][6008];
int ans;
IL int dis(int a,int b){return abs(a-b);}
IL bool ok(int x,int y)
{
    if(x<0 || y<0 || x>5000 || y>5000 || !res[x][y])return false;
    return true;
}
IL void search(int px,int py,int nx,int ny)
{
    int delx=dis(px,nx),dely=dis(py,ny);
    if(ok(px+dely,py-delx) &&ok(nx+dely,ny-delx))
        ans=std::max(ans,delx*delx+dely*dely);
    else if(ok(px-dely,py+delx) && ok(nx-dely,ny+delx))
        ans=std::max(ans,delx*delx+dely*dely);
     //感覺少考慮了斜率為負的那一種情況,但的確是可以AC的.
     /*
     我們也可以加上判斷斜率為負的情況.
    else if(ok(px+dely,py+delx) && ok(nx+dely,ny+delx))
        ans=std::max(ans,delx*delx+dely*dely);
    else if(ok(px-dely,py-delx) && ok(nx-dely,ny-delx))
        ans=std::max(ans,delx*delx+dely*dely);
     難道數據水?
     */
}
int main(void)
{
    in(n);
    for(RI i=1;i<=n;i++)
        in(x[i]),in(y[i]),res[x[i]][y[i]]=true;
    for(RI i=1;i<=n;i++)
        for(RI j=1;j<=n;j++)
            if(i!=j)search(x[i],y[i],x[j],y[j]);
    printf("%d",ans);
}

裏面的delx*delx+dely*dely勾股定理的內容,就不用我多說了吧.

(逃

p1959 遺址[NOI導刊2009普及(6)]