合併類動態規劃專題訓練

話說,我已經很久沒有寫博客了,其實裏面有很大一段的故事的。。。
不管了,現在都已經11號了,還有7天考試,真是着實不爽啊!
好了,回到正題了,這周我們練了一個合併類的動態規劃:
0多邊形【推薦】
1 【NOIP動態規劃專題】等腰三角形
2 【NOIP動態規劃專題】能量項鍊
3 行政劃分【難】

0 多邊形【推薦】

  多邊形是一個單人玩的遊戲,開始時有一個N個頂點的多邊形。如圖,這裏N=4。每個頂點有一個整數標記,每條邊上有一個“+”號或“*”號。邊從1編號到N。
  第一步,一條邊被拿走;隨後各步包括如下:
  選擇一條邊E和連接着E的兩個頂點V1和 V2;
  得到一個新的頂點,標記爲V1與V2通過邊E上的運算符運算的結果。
  最後,遊戲中沒有邊,遊戲的得分爲僅剩餘的一個頂點的值。
  寫一個程序,對於給定一個多邊形,計算出可能的最高得分以及操作方法。
  【數據範圍】
  3<=N<=50
  不管怎麼操作,中間結果一定在[-32768,32767]範圍內。

分析

好了對於這題,我們可以先枚舉一條被刪的邊,然後我們就可以把這個多邊形展開
這是很重要的思想:一個圖形很難dp,而把它變成一列點便變得很好dp了。
於是我們設f[i,j]表示已經計算出第i個點到第j個點的操作最大值,
明顯的f[i,j]=max(f[i,k]&f[k,j])&表示計算的符號。
那麼這樣就完成了嗎?很明顯的不是,因爲這題裏面有負數!
有負數就意味着兩個負數的積有可能超過兩個正數的積,所以在這裏我們再設:
g[i,j]表示最小的值。
轉移都差不多的。

【NOIP動態規劃專題】等腰三角形

給定一個正N邊形,可以通過連線將這個多邊形分割成N-2個三角形,問這N-2個三角形中恰有k個等腰三角形的分割方法有多少?這個值可能很大,輸出對9397取模的結果。

分析

其實上面的題目就是這題的基礎,我們也一樣把點都展開來,那麼方程應該是:
f[i,j,k]表示i到j的點形成k個等腰三角形的方案數。
f[i,j,k]=l<jl=i+1r<=kr=0f[i,l,r]f[l,j,krpd()]
這裏的方程和上面唯一不一樣的是減了一個pd(),這個是指有可能l和i和j的連線會形成一個等腰三角形。
而情況請讀者自己考慮。

【NOIP動態規劃專題】能量項鍊

比較水,不講了。

行政劃分【難】

這題是重點!
某國領土形狀十分奇特,可以將它近似地看作是一個有N 個頂點的凸多邊形 。現在該國政府想要將它劃分爲(N-2)個互不重疊的行政區域,並希望每個區域的形狀都是三角形,三角形的頂點即爲凸多邊形的頂點。該國政府又出於資源、人口、宗教等多方面的考慮,希
望得到一種劃分方案,使得(N-2)塊區域的面積的方差最小
這裏寫圖片描述
現在該國政府官員找到了你,希望你能夠幫助他們解決這個問題。

Input

第一行是一個整數N (4≤N≤50), 表示凸多邊形頂點的個數
接下來的N 行,每行有兩個實數X、Y(-1000000≤X、Y≤1000000),分別表示按比例縮小後的凸多邊形頂點在座標系內的橫縱座標值。

你只要輸出一個實數,即最小方差值 (保留到百分位)。

注意:凸多邊形的頂點不一定按順序給出。

分析

我們先不考慮如何求凸邊形的面積如何去求,先考慮如何dp。
這題還是多邊形,於是我們考慮將其轉換爲一些點列,類似的:
f[i,j]表示從第i個點到第j個點之間的面積的最小的方差
(之所以它可以dp是因爲可以轉換成各個三角形之間的決策,而且最後的答案和sqrt()和/(n-2)運算沒有關係)
(但這裏注意dp時點的順序是有關係的,所以後面會寫如何求點的順序)
所以,就可以f[i,j]=min(f[i,j],f[i,k]+f[k,j]+sqr(sum(i,k,j)-ave)),
sum(i,j,k)表示的是邊長爲i,j,k的長度的三角形的面積。用海倫公式求。
ave指多邊形的面積/(n-2),即平均值。
那麼現在的問題就是如何求凸多邊形的面積。
我們會想到劃分成三角形的面積,但是如何確定點的順序呢?
這裏介紹一個函數:
atan2(y,x)的值爲座標爲(x,y)與(0,0)的連線與x軸的正半軸的夾角x*pi/180.
那麼我們是否可以隨便確定一個點(x,y),然後求出其他點(x1,y1)的atan2(y1-y,x1-x)值
排個序後是否就是我們點的順序,dp的順序呢?

基本思想是這樣的,但是:
1.我們選爲基準的點必須是y座標最小的同時還是相同y座標最小的x座標最小。
爲什麼呢,因爲這樣就不會出現負數的角度,會方便很多(這個自己推吧)
2.而且當多個點與基準點的y座標相同時,它們的順序是按照x座標排的,即這些點的atan2值爲0,的時候。
這樣就可以保證不會出錯了。

代碼

0多邊形

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=105,maxlongint=2147483647;
int n,a[N*2],f[N][N],g[N][N],b[N],an[N],d[N];
char ch;
int main(){
    scanf("%d",&n);
    int st=1,en=n,op=0;
    for(int i=1;i<=n;i++){
        scanf("%c",&ch);
        scanf("%c",&ch);
        scanf("%d",&a[i]);
        if (ch=='t') op=1;else op=0;
        b[i]=op;st=i;en=i+1;
    }
    int ans=-maxlongint;
    for(int t=1;t<=n;t++){
    int bz=1;
    for(int i=t;i<=n;i++,bz++) d[bz]=i;
    for(int i=1;i<=t-1;i++,bz++) d[bz]=i;
    memset(f,128,sizeof(f));
    memset(g,127,sizeof(g));
    for(int i=1;i<=n;i++) f[i][i]=g[i][i]=a[d[i]];
    for(int i=1;i<=n-1;i++){
       for(int st=1;st+i<=n;st++){
          for(int j=0;j<i;j++)
            if (b[d[st+j+1]])
            f[st][st+i]=max(f[st][st+i],f[st][st+j]+f[st+j+1][st+i]),
            g[st][st+i]=min(g[st][st+i],g[st][st+j]+g[st+j+1][st+i]);
            else 
            f[st][st+i]=max(max(f[st][st+i],f[st][st+j]*f[st+j+1][st+i]),g[st][st+j]*g[st+j+1][st+i]),
            g[st][st+i]=min(min(g[st][st+i],g[st][st+j]*g[st+j+1][st+i]),g[st][st+j]*f[st+j+1][st+i]);
        }
    }
    an[t]=f[1][n];ans=max(ans,an[t]);
    }
    printf("%d\n",ans);
    for(int i=1;i<=n;i++)if (an[i]==ans) printf("%d ",i);
}

等腰三角形

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int N=55,mo=9397;
int n,m,f[N][N][N];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) f[i][i+2][1]=f[i][i+1][0]=1;
    for(int len=3;len<=n-1;len++){
        for(int i=1;i<=n-len;i++){
            for(int k=1;k<=m;k++){
            if (i==2&&i+len==5&&k==2)
            n=n;
               for(int l=i+1;l<i+len;l++){
                int op=0;
                if (n-(i+len)+i-1==(i+len)-l-1||l-i-1==n-(i+len)+i-1||(i+len-l)==l-i) op=1;
                if (((i+len)==n)&&(i==n-l||n-l==len||l==i)) op=1;
                  for(int r=0;r<=k;r++)
                     f[i][i+len][k]+=f[i][l][r]*f[l][i+len][k-r-op],f[i][i+len][k]%=mo;
                }
            }
        }
    }
    printf("%d",f[1][n][m]);
}

能量項鍊

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=205;
int n,a[N*2],f[N][N];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),a[i+n]=a[i],a[i+n+n]=a[i];
    n*=2;
    for(int i=1;i<=n;i++){
       for(int st=1;st+i<=n;st++){
          for(int j=0;j<i;j++)
            f[st][st+i]=max(f[st][st+i],f[st][st+j]+f[st+j+1][st+i]+a[st]*a[st+j+1]*a[st+i+1]);
        }
    }
    int ans=0;
    for(int i=1;i<=n/2;i++) 
    ans=max(ans,f[i][i+(n/2)-1]);
    printf("%d",ans);
}

行政劃分

#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#define db double 
using namespace std;
const int N=55;
int n;
struct xgf{
    db x,y,z;
}a[N];
bool cmp(xgf a,xgf b){
    return (a.z<b.z||(a.z==b.z&&a.x<b.x));
}
db sqr(db x){
    return x*x;
}
db slen(int x,int y){
    return sqrt(sqr(a[x].x-a[y].x)+sqr(a[y].y-a[x].y));
}
db sum(db a,db b,db c){
    db p=(a+b+c)/2*1.0;
    return sqrt(p*(p-a)*(p-b)*(p-c));
}
int main(){
    scanf("%d",&n);
    db mi=2147483647.0;
    db ma=mi;
    int k;
    for(int i=1;i<=n;i++){
        scanf("%lf%lf",&a[i].x,&a[i].y);
        if (mi>a[i].y||mi==a[i].y&&ma>a[i].x) mi=a[i].y,ma=a[i].x,k=i;
    }
    for(int i=1;i<=n;i++) 
    if (i!=k)a[i].z=atan2(a[i].y-a[k].y,a[i].x-a[k].x);
    sort(a+1,a+n+1,cmp);
    db s=0;
    for(int i=3;i<=n;i++){
        s+=sum(slen(1,i),slen(1,i-1),slen(i,i-1));
    }
    s=s/(n-2)*1.0;
    db f[N][N];
    memset(f,127,sizeof(f));
    for(int i=1;i<=n-2;i++) f[i][i+2]=sqr(sum(slen(i,i+1),slen(i,i+2),slen(i+1,i+2))-s);
    for(int i=1;i<=n;i++) f[i][i+1]=0;
    for(int len=1;len<=n-1;len++){
        for(int i=1;i<=n-len;i++){
            for(int j=i+1;j<i+len;j++){
                f[i][i+len]=min(f[i][i+len],f[i][j]+f[j][i+len]+
                sqr(sum(slen(i,j),slen(i,i+len),slen(j,i+len))-s));
            }
        }
    }
    printf("%.2lf",sqrt(f[1][n]/(n-2)*1.0));
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章