[ACM]【線性DP】石子合併問題

重做1月的題,都很簡單補一下記錄。

相鄰石子合併

傳送門
在這裏插入圖片描述
注意,得分是累加的。
別忘了多組輸入每次都要清零。

#include<bits/stdc++.h>
using namespace std;
int a[104];
int dp[104][104],dp2[103][104];
int sum[104];
const int inf=1e9+7;
int main(){
	int n;
	while(~scanf("%d",&n)){
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			sum[i]=sum[i-1]+a[i];//前綴和
			dp[i][i]=0;dp2[i][i]=0;
		} 
		for(int k=1;k<=n-1;k++){//枚舉長度
			for(int i=1;i<n;i++){
				int j=i+k;
				if(j>n) break;
				dp[i][j]=inf;
				//下面這句相當於初始化!因爲多組數據輸入,每次都要清零,不然WA
				dp2[i][j]=0;
				int tmp=sum[j]-sum[i-1];
				for(int m=i;m<j;m++){
					dp[i][j]=min(dp[i][m]+dp[m+1][j]+tmp,dp[i][j]);
					dp2[i][j]=max(dp2[i][m]+dp2[m+1][j]+tmp,dp2[i][j]);
				}
			}
		}
		printf("%d %d\n",dp[1][n],dp2[1][n]);
	}
}

環形相鄰石子合併

傳送門
在這裏插入圖片描述
化曲爲直

#include<bits/stdc++.h>
using namespace std;
int stone[102];
int sum[202];
int dp[202][202];
int dp2[202][202];
const int inf=1e9;
int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&stone[i]);
		sum[i]=sum[i-1]+stone[i];
	}
	for(int i=n+1;i<=2*n;i++)sum[i]=sum[i-1]+stone[i-n];
	for(int len=1;len<=n-1;len++){
		for(int i=1;i<=2*n-1;i++){
			int j=i+len;
			if(j>2*n)break;
			dp2[i][j]=inf;
			for(int k=i;k<j;k++){
				dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
				dp2[i][j]=min(dp2[i][j],dp2[i][k]+dp2[k+1][j]+sum[j]-sum[i-1]);
			}
		}
	}
	int maxn=0,minn=inf;
	//最後尋找最好的段落!
	for(int i=1;i<=n;i++){
		maxn=max(dp[i][i+n-1],maxn);
		minn=min(dp2[i][i+n-1],minn);
	}
	printf("%d\n%d\n",minn,maxn);
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章