重做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);
}