NKOJ 1137 石子合併問題 區間dp

2021-06-15 05:56:54 字數 1753 閱讀 9836

前幾天做的第一道區間dp的題。下午開始備戰最後一門考試。又積壓了好多題沒寫題解了……

思路:我是看這篇文章入門的 深入分析區間型動態規劃,解題思路裡面已經說得很清楚了,下面貼我的**

其中dp[i][j]表示,從第 i 個數到第 j 個數相加的最小或最大代價

#include #include #include #define max(a,b) ((a)>(b)?(a):(b))

#define min(a,b) ((a)<(b)?(a):(b))

const int inf=0x3fffffff;

const int n=105;

int data[2*n],sum[2*n][2*n];

int dp1[2*n][2*n],dp2[2*n][2*n]; //dp1儲存最小,dp2儲存最大

int main ()

dp1[i][i]=dp2[i][i]=0;

} for (i=1;i<=n;i++)

for (j=1;j<=2*n-i;j++)

for (k=j;k<=i+j-1;k++)

int ans1=inf,ans2=0;

for (i=1;i<=n;i++) //列舉長度為n的區間

printf("%d\n%d\n",ans1,ans2);

}return 0;

}

下面貼一下別人的思路和**,複雜度比我的方法好一些。

以下**:

1、因為石子圍成了一圈,所以先要將n堆的石子複製到第n+1~第2*n堆,這樣才能保證無論從哪一堆開始合併,都能取到任意長度的石子堆。

2、dp[i][j] 表示從第i堆開始合併長度為j堆的石子的最優情況,這樣可以求得從任意堆開始長度為x的石子堆的最優情況;

3、sum[i]表示從i開始的長度為x(變長)的石子堆所有石子總數。

4、dp[i][j] =  max + sum[i];  ( 1<=k<=n )

但是,必須注意此處的dp[i+k][j-k],若迴圈只到n,可能會越界即可能取到沒有算過的值,例如當n=5時,dp[5][4] = max(或min) + sum[5]; 此處的dp[6][3]就沒有被賦過值,導致「越界」。由於此處的dp[6][3]實際上相當於第1、2、3堆石子合併的最優解,即dp[1][3]。所以當(i+k)%n!=0時,dp[(i+k)%n][j+k] = dp[i+k][j-k];

所以最後:dp[i][j] = max(或min) + sum[i];

5、還有個要注意的長度為1的石子合併的得分一定為0。

#include #include #define max(data,b) ((data)>(b)?(data):(b))

#define min(data,b) ((data)<(b)?(data):(b))

const int inf=0x3fffffff;

const int n=105;

int data[2*n],sum[n];

int dp1[n][n],dp2[n][n]; //dp1儲存最小,dp2儲存最大

int main ()

dp1[i][1]=dp2[i][1]=0;

} int ans1=inf,ans2=-inf;

for (j=3;j<=n;j++)

for (i=1;i<=n;i++)

{sum[i]+=data[i+j-1];

int t1,t2;

for (k=1;k

3 3 石子合併問題

問題描述 在乙個圓形操場的四周擺放著 n 堆石子。現要將石子有次序地合併成一堆。規定每次只 能選相鄰的 2 堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的得分。試設計一 個演算法,計算出將 n 堆石子合併成一堆的最小得分和最大得分。程式設計任務 對於給定 n 堆石子,程式設計計算合併成一堆的...

282 石子合併

設有n堆石子排成一排,其編號為1,2,3,n。每堆石子有一定的質量,可以用乙個整數來描述,現在要將這n堆石子合併成為一堆。每次只能合併相鄰的兩堆,合併的代價為這兩堆石子的質量之和,合併後與這兩堆石子相鄰的石子將和新堆相鄰,合併時由於選擇的順序不同,合併的總代價也不相同。例如有4堆石子分別為 1 3 ...

2298 石子合併

2008年省隊選拔賽山東 時間限制 1 s 空間限制 256000 kb 題目等級 gold 在乙個操場上擺放著一排n堆石子。現要將石子有次序地合併成一堆。規定每次只能選相鄰的2堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的得分。試設計乙個演算法,計算出將n堆石子合併成一堆的最小得分。輸入描...