区间dp刷题
思路:成环啦,就把它复制一遍再求呗,每次合并两堆石子,那么不管是怎样合并,最后一次合并都会得到sum(这两堆石子数)的分数再加上分别得到这两堆石子所得分数dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j])dp[i][j]+=sum[i…j]代码如下:#include<iostream>#include<...
·
思路:
成环啦,就把它复制一遍再求呗,
每次合并两堆石子,那么不管是怎样合并,最后一次合并都会得到sum(这两堆石子数)的分数
再加上分别得到这两堆石子所得分数
dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j])
dp[i][j]+=sum[i…j]
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
typedef pair<int,int>P;
const int INF=0x3f3f3f3f;
const int N=205;
int a[2*N],sum[2*N];
int dp[2*N][2*N],dp1[2*N][2*N];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
a[i+n]=a[i];
}
for(int i=1;i<=2*n;i++){
sum[i]=sum[i-1]+a[i];
}
//dp[i][j]:=i到j合并
for(int r=2;r<=2*n;r++){
for(int i=1;i<=2*n-r+1;i++){//开头
int j=i+r-1;//结尾
dp[i][j]=dp[i][i]+dp[i+1][j];
dp1[i][j]=dp1[i][i]+dp1[i+1][j];
for(int k=i+1;k<j;k++){//中间
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);
dp1[i][j]=max(dp1[i][j],dp1[i][k]+dp1[k+1][j]);
}
dp[i][j]+=sum[j]-sum[i-1];
dp1[i][j]+=sum[j]-sum[i-1];
}
}
int mx=0,mi=1e9;
for(int i=1;i<=n;i++){
mi=min(mi,dp[i][i+n-1]);
mx=max(mx,dp1[i][i+n-1]);
}
printf("%d\n%d\n",mi,mx);
}
思路:
要注意的是,这有三边形以上的才有结果,所以,区间大小从3开始
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
typedef pair<int,int>P;
const int INF=0x3f3f3f3f;
const int N=55,Mod=10000;
ll a[N];
struct Bignum{
int len,s[500];
Bignum(){
memset(s,0,sizeof(s));
len = 1;
}
Bignum operator +(const Bignum &A)const{
Bignum B;
B.len = max(len,A.len);
for(int i = 0;i< B.len; i++){
B.s[i] =B.s[i] + A.s[i] + s[i];
B.s[i+1] += B.s[i]/10;
B.s[i] = B.s[i]%10;
}
if(B.s[B.len]) B.len ++;
return B;
}
bool operator <(const Bignum &A)const{
if(len != A.len) return len < A.len;
for(int i= len-1; i >=0 ; i--){
if(s[i] != A.s[i]) return s[i] < A.s[i];
}
return false;
}
Bignum operator *(const Bignum &A)const{
Bignum B;
B.len = len+A.len-1;
for(int i = 0;i< A.len; i++){
for(int j=0;j< len;j++){
B.s[i+j] =B.s[i+j] + A.s[i] * s[j];
B.s[i+j+1] += B.s[i+j]/10;
B.s[i+j] = B.s[i+j]%10;
}
}
if(B.s[B.len]) B.len ++;
return B;
}
void write(){
int k = len-1;
while(s[k]==0 && k >0) k--;
for(int i = k;i>=0;i--) cout << s[i];
}
}dp[51][51];
Bignum change(long long x){ //将一个整数变成数组存储的Bignum类型
Bignum t;
int cnt =0;
while(x!=0){
t.s[cnt++] = x%10;
x /= 10;
}
t.len = cnt;
return t;
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
for(int r=3;r<=n;r++){
for(int i=1;i<=n-r+1;i++){
int j=i+r-1;
dp[i][j].len=400;
dp[i][j].s[399]=1;
for(int k=i+1;k<j;k++){
Bignum t=change(a[i])*change(a[j])*change(a[k]);
Bignum tp=t+dp[i][k]+dp[k][j];
if(tp<dp[i][j])dp[i][j]=tp;
}
}
}
dp[1][n].write();
}
思路:
题意花里胡哨的_(:з」∠)_
其实就是:所有数字,刚开始都是分隔开的,然后,两两合并,合并所得的值就是(合并后区间左端点+合并后区间右端点)*分割点。
转移方程:dp[i][j]=dp[i][k]+dp[k+1][j]+(a[i]+a[j])*a[k]
输出的时候用bfs输出!
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
typedef pair<int,int>P;
const int INF=0x3f3f3f3f;
const int N=305;
int a[N],n;
int dp[N][N];
int se[N][N];
void output(){
queue<P>Q;
printf("%d",se[1][n]);
Q.push(P(1,se[1][n]));
Q.push(P(se[1][n]+1,n));
while(Q.size()){
P p=Q.front();
Q.pop();
if(p.first==p.second)continue;
int t=se[p.first][p.second];
printf(" %d",t);
Q.push(P(p.first,t));
Q.push(P(t+1,p.second));
}
printf("\n");
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int r=2;r<=n;r++){
for(int i=1;i<=n-r+1;i++){
int j=i+r-1;
for(int k=i;k<j;k++){//从k处合并
int t=dp[i][k]+dp[k+1][j]+(a[i]+a[j])*a[k];
if(dp[i][j]<t){
dp[i][j]=t;
se[i][j]=k;
}
}
}
}
printf("%d\n",dp[1][n]);
output();
}
更多推荐
已为社区贡献4条内容
所有评论(0)