1. 程式人生 > >藍橋杯/nyoj 737 合併石子 區間dp+平行四邊形優化

藍橋杯/nyoj 737 合併石子 區間dp+平行四邊形優化

問題描述   在一條直線上有n堆石子,每堆有一定的數量,每次可以將兩堆相鄰的石子合併,合併後放在兩堆的中間位置,合併的費用為兩堆石子的總數。求把所有石子合併成一堆的最小花費。 輸入格式   輸入第一行包含一個整數n,表示石子的堆數。
  接下來一行,包含n個整數,按順序給出每堆石子的大小 。 輸出格式   輸出一個整數,表示合併的最小花費。 樣例輸入 5
1 2 3 4 5 樣例輸出 33 資料規模和約定

  1<=n<=1000, 每堆石子至少1顆,最多10000顆。

思路:

第一個區間dp的題,一開始還以為是貪心。。。結果不是   貪心演算法在子過程中得出的解只是區域性最優,而不能保證使得全域性的值最優。

這個題就是三層的for迴圈 

最外面一層表示區間的長度 因為自己一堆時長度為1不合並 所以len從2到n

第二層列舉的起點位置,i從1到n-len+1,通過起點位置和區間長度計算出終止點位置j=i+len-1

第三層  知道起始位置和末位置,我們來 列舉合併斷開的位置 k從i到j-1 從而通過一個個子問題找到最優解

動態轉移方程 

dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);

結果在藍橋杯上超時了..應該把min函式去掉在優化一下會卡線過吧

90分程式碼

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1111;
int dp[maxn][maxn],sum[maxn];
int a[maxn];
int main()
{
	int i,n,j,k,len;
	while(~scanf("%d",&n))
	{
		memset(sum,0,sizeof(sum));
		for(i=1;i<=n;i++)
		{
			dp[i][i]=0;
			scanf("%d",&a[i]);
			sum[i]+=sum[i-1]+a[i];
		}
		for(len=2;len<=n;len++) 
		{
			for(i=1;i<=n-len+1;i++)
			{
				j=i+len-1;
				 dp[i][j]=inf;
				 for(k=i;k<=j-1;k++)
				 dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
					
			}	
		}
		printf("%d\n",dp[1][n]);
	}
	return 0;
}
 


網上學了一下 這個題需要用到一個平行四邊形優化 

具體證明看這裡。。反正我是沒看懂,感覺就是加了一個 s[i][[j記錄dp[i][j]之間的一個最優分割點 就把k限定在了 s[i][j-1]...s[i+1][j]之間。至於為啥我也是似懂非懂

可以優化到30 -40ms

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1111;
int a[maxn],dp[maxn][maxn],sum[maxn],s[maxn][maxn];
int main()
{
	int i,j,k,len,n;
	while(scanf("%d",&n)!=EOF)
	{
		memset(sum,0,sizeof(sum));
		memset(dp,0,sizeof(dp));
		memset(s,0,sizeof(s));
		for(i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			s[i][i]=i;
			dp[i][i]=0;
			sum[i]+=sum[i-1]+a[i];
		}
		for(len=2;len<=n;len++)
		{
			for(i=1;i<=n-len+1;i++)
			{
				j=i+len-1;
				dp[i][j]=inf;
				for(k=s[i][j-1];k<=s[i+1][j];k++)
				{
					if(dp[i][j]>dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1])
					{
						dp[i][j]=dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1];
						s[i][j]=k;
					}
				}
			}
		}
		printf("%d\n",dp[1][n]);
	}
	return 0;
}


相關推薦

藍橋/nyoj 737 合併石子 區間dp+平行四邊形優化

問題描述   在一條直線上有n堆石子,每堆有一定的數量,每次可以將兩堆相鄰的石子合併,合併後放在兩堆的中間位置,合併的費用為兩堆石子的總數。求把所有石子合併成一堆的最小花費。 輸入格式   輸入第一行包含一個整數n,表示石子的堆數。   接下來一行,包含n個整數,按

HDU3480_區間DP平行四邊形優化

做到現在能一眼看出來是區間DP的問題了 也能夠知道dp[i][j]表示前  i  個節點被分為  j  個區間所取得的最優值的情況 cost[i][j]表示從i到j元素區間中的值,這裡可以直接排序後簡單求出——也就是我們的代價函式 這樣其實就能夠做出來了,但是空間複

藍橋訓練:合併石子

問題描述   在一條直線上有n堆石子,每堆有一定的數量,每次可以將兩堆相鄰的石子合併,合併後放在兩堆的中間位置,合併的費用為兩堆石子的總數。求把所有石子合併成一堆的最小花費。 輸入格式   輸入第一行包含一個整數n,表示石子的堆數。   接下來一行,包含

[NOI1995]石子合併區間DP

題目連結: [NOI1995]石子合併   思路: 區間DP經典例題,可以把前n-1堆石子一個個移到第n個後面,那樣環就變成了線,即現在有2*n-1堆石子需要合併。   程式碼: #include <iostream> #include

石子合併區間DP

一.試題在一個園形操場的四周擺放N堆石子(N≤100),現要將石子有次序地合併成一堆。規定每次只能選相鄰的兩堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。編一程式,由檔案讀入堆數N及每堆的石子數(≤20),①選擇一種合併石子的方案,使得做N-1次合併,得分

石子合併區間dp

有N堆石子排成一排,每堆石子有一定的數量。現要將N堆石子併成為一堆。合併的過程只能每次將相鄰的兩堆石子堆成一堆,每次合併花費的代價為這兩堆石子的和,經過N-1次合併後成為一堆。求出總的代價最小值

石子合併(一) 區間DP

石子合併(一)(傳送門) 時間限制:1000 ms | 記憶體限制:65535 KB 難度:3 描述 有N堆石子排成一排,每堆石子有一定的數量。現要將N堆石子併成為一堆。合併的過程只

第四屆藍橋真題 連號區間

max 排列 add sca ace box 題目 initial for 本來想練習並查集,然後在看官網提示這是並查集類型題目,上來先默寫了一下並查集,想了半天並查集怎麽寫。。我呸,並查集。。這裏找規律。。區間的【最大值-最小值】=【區間長度】,直接枚舉。。。討厭這種找規

藍橋歷屆試題 連號區間數:枚舉(含樣例解釋)

簡單 表示 main 排列 定義 head clas 單個 ace 問題描述 小明這些天一直在思考這樣一個奇怪而有趣的問題: 在1~N的某個全排列中有多少個連號區間呢?這裏所說的連號區間的定義是: 如果區間[L, R] 裏的所有元素(即此排列的第L個到第R個元

區間dp四邊形不等式優化 學習筆記

部落格目錄 很久之前在網上看了傳說中的四邊形不等式,然後現在發現忘光了。趁比賽前夕趕快拿來熟悉一下。 一、引入 形如: dp[i][j]=min{dp[i][k]+dp[k+1][j]+cost[i][j]} 的狀態轉移方程,如果不加優化的話ijk三層迴圈O(n

DP平行四邊形優化

Luogu P4767 [IOI2000]郵局 #include <bits/stdc++.h> using namespace std; int n,m,a[3005],mk[3005][

區間動態規劃——平行四邊形優化

區間動態規劃:   針對區間問題的最優解而產生的一種動態規劃演算法,通常以區間為狀態來記錄最優解,故狀態為O(N^2)   而轉移則是列舉這段區間中的決策點,通過兩個更小的區間最優解得合併來得到這段區間的狀態,故轉移為(N)   則狀態O(N^2),轉移O(N),總時間

用一題來說明dp平行四邊優化

poj 1160  題意:給出n個村莊,村莊是一條直線排好的,並且給出每個村莊到直線最左邊初始點的距離。現在要建立m個郵局,於是引入一個距離S{各個村莊到最近的郵局的距離和}。那麼現在問題來了如何使得這個S的值最小? 題解:定義這樣的方程 dp[i][j] = min{ d

nyoj 737 石子合併(一) 【區間dp

石子合併(一) 時間限制:1000 ms  |  記憶體限制:65535 KB 難度:3 描述    有N堆石子排成一排,每堆石子有一定的數量。現要將N堆石子併成為一堆。合併的過程只能每次

NYOJ 737 石子合併(一)(區間dp)

石子合併(一) 時間限制:1000 ms  |  記憶體限制:65535 KB 難度:3 描述    有N堆石子排成一排,每堆石子有一定的數量。現要將N堆石子併成為一堆。合併的過程只能每次將相鄰的兩堆石子堆成一堆,每次合併花費的代價為這兩堆石子的和,經過N-1次合

NYOJ題目737石子合併(一)(區間dp

石子合併(一) 時間限制:1000 ms  |  記憶體限制:65535 KB 難度:3 描述    有N堆石子排成一排,每堆石子有一定的數量。現要將N堆石子併成為一堆。合併的過程只能每次將

nyoj 737 石子合並(區間DP

using lac padding gin height space outline style 每次 737-石子合並(一) 內存限制:64MB 時間限制:1000ms 特判: No通過數:28 提交數:35 難度:3 題目描

藍橋 合併石子 DP+四邊形不等式優化

  演算法提高 合併石子   時間限制:2.0s   記憶體限制:256.0MB 問題描述   在一條直線上有n堆石子,每堆有一定的數量,每次可以將兩堆相鄰的石子合併,合併後放在兩堆

藍橋 —— 石子合併問題 —— Dp

題目大意是說給你一個n,代表有n堆石子。然後給你n個數,分別表示每堆石子的個數。 要求是每次只能合併相鄰的兩堆石子,每合併一次就把ans += 需要被合併的兩堆石子的個數。 問怎樣合併使得最後所需要的費用 ans 值最小。 解題思路:這道題不能夠用區域性最優的貪心思想

區間DP入門之 石子歸併問題 NYOJ 737

分析:要求n個石子歸併,我們根據dp的思想劃分成子問題,先求出每兩個合併的最小代價,然後每三個的最小代價,依次知道n個。 定義狀態dp [ i ] [ j ]為從第i個石子到第j個石子的合併最小代