[答题卡] 2018.7.16 新高一动态规划练习3 序列型

1.锯齿队形

#include<algorithm>
#include<iostream>
#include<fstream>
#include<cstdio>
#define Max 30005
using namespace std;

int h[Max],f[Max],g[Max];
//f(i)代表前i个元素最后为升序的抖动序列的最大长度 
//g(i)代表前i个元素最后为降序的抖动序列的最大长度 

int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&h[i]);
	}
	
	f[1]=1;g[1]=1;
	for(int i=2;i<=n;i++){
		if(h[i]==h[i-1]){
			f[i]=f[i-1];
			g[i]=g[i-1];
		}
		if(h[i]>h[i-1]){
			f[i]=max(f[i-1],g[i-1]+1);
			g[i]=g[i-1];
		}
		if(h[i]<h[i-1]){
			f[i]=f[i-1];
			g[i]=max(f[i-1]+1,g[i-1]);
		}
	}
	printf("%d",n-max(f[n],g[n]));
	return 0;
}

2.花匠

//话说这道题就交P1的代码都能过呢…

#include<algorithm>
#include<iostream>
#include<fstream>
#include<cstdio>
#define Max 100005
using namespace std;

int h[Max],f,g;
//f代表前i个元素最后为升序的抖动序列的最大长度 
//g代表前i个元素最后为降序的抖动序列的最大长度 

int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&h[i]);
	}
	
	f=1;g=1;
	for(int i=2;i<=n;i++){
		if(h[i]>h[i-1]){
			f=max(f,g+1);
		}
		else if(h[i]<h[i-1]){
			g=max(f+1,g);
		}
	}
	printf("%d",max(f,g));
	return 0;
}

3.乘积最大

#include<algorithm>
#include<iostream>
#include<fstream>
#include<cstdio>
using namespace std;

char cha[15];
int num[15],t[15][10]={0},f[15][15]={0};

int main(){
	int N,K;
	scanf("%d%d",&N,&K);K++;
	scanf("%s",cha+1);
	for(int i=1;i<=N;i++){
		num[i]=cha[i]-'0';
	}
	
	for(int i=1;i<=N;i++){
		for(int j=i;j<=N;j++){
			t[i][j]=t[i][j-1]*10+num[j];
		}
	}//t[i][j]:在num数组中,由下标i-j组成的整数
	
	for(int i=1;i<=N;i++){
		f[i][1]=t[1][i];
	}//初始化分一组的情况
	
	//函数原型: 
	//f[n][k]:把n个数分成k组的情况中,乘积最大的值 
	 
	for(int k=2;k<=K;k++){//k=2:分一组已经考虑了 
		for(int n=k;n<=N;n++){//n=k:要分k组,至少要有k个元素 
			for(int i=k-1;i<n;i++){
				//i=k-1:前i个的元素分k-1组 
				f[n][k]=max(f[i][k-1]*t[i+1][n],f[n][k]);
			}
		}
	}
	printf("%d",f[N][K]);
	return 0;
}

4.渡河问题

公无渡河,公竟渡河。渡河而死,其奈公何?突然想到 |ू・ω・` )

#include<algorithm>
#include<iostream>
#include<fstream>
#include<cstdio>
using namespace std;

int t[2505]={0},f[2505];//带n头牛去所需要的时间 
 
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	int s=m;
	for(int i=1;i<=n;i++){
		int a;
		scanf("%d",&a);
		s+=a;t[i]=s;
	}
	
	f[1]=t[1]+m;
	for(int i=2;i<=n;i++){
		f[i]=t[i]+m;
		for(int j=1;j<=i-1;j++){
			if(f[i]>f[i-j]+t[j]+m){
				f[i]=f[i-j]+t[j]+m;
				//分成两部分:f[n-1],t[1] || f[n-2],t[2]…… 
			}
		}
	}
	printf("%d\n",f[n]-m);
	return 0;
}
/*f[i]=min(f[i-j]+t[j]+m)  {1<=i<=n,1<=j<=i-1}
  f[i]=t[i]+m(初始化)*/

###5.马棚问题
//当年第一次学DP时这道题可是一坨阴影…

#include<algorithm>
#include<iostream>
#include<fstream>
#include<cstdio>
#define OO 999999999
using namespace std;

int black[505],f[505][505];
//black[i]:第1-i匹马中黑马数 
//f[n][k]:将n匹马放入k个马厩里的系数总和的最小值 

int main(){
	int N,K;
	scanf("%d%d",&N,&K);
	for(int i=1;i<=N;i++){
		int color;
		scanf("%d",&color);
		black[i]=black[i-1]+color;
		
		f[i][1]=black[i]*(i-black[i]);//边界:i匹马分一组 
	}
	
	for(int dk=2;dk<=K;dk++){
		for(int dn=dk;dn<=N;dn++){
			f[dn][dk]=OO;//求最小值,初始赋极大值 
			for(int i=dk-1;i<=dn-1;i++){
				int B_horse=black[dn]-black[i];
				f[dn][dk]=min(f[dn][dk],f[i][dk-1]+B_horse*((dn-i)-B_horse));
				//min(前i个元素分成k-1组的不愉快系数)+第k组的不愉快系数 
			}
		}
	}
	printf("%d",f[N][K]);
	return 0;
}

6.数字游戏

#include<algorithm>
#include<iostream>
#include<fstream>
#include<cstdio>
#define MAXN 1000000000
using namespace std;

int N,M,ansmax=-MAXN,ansmin=MAXN;
int num[55],prefix[55]={0};
int f_min[55][15]={0},f_max[55][15]={0};

void prefix_sum(){
	for(int i=1;i<=N;i++){
		prefix[i]=prefix[i-1]+num[i];
	}
}//用前缀和的思想,算出分一组时的和 

void roll(){
	for(int i=1;i<=N;i++){
		num[i-1]=num[i];
	}
	num[N]=num[0];
} 

int main(){
	scanf("%d%d",&N,&M);
	for(int i=1;i<=N;i++){
		scanf("%d",&num[i]);
	}
	
	for(int cnt=1;cnt<=N;cnt++){//N种排序方式都要算 
		prefix_sum();
		
		for(int i=1;i<=N;i++){
			f_min[i][1]=(prefix[i]%10+10)%10;
			f_max[i][1]=(prefix[i]%10+10)%10;
		}//初始化分一组的情况
		 
		//f[n][m]:n个元素分成m组,和的最小/大值(n>=m)
		for(int m=2;m<=M;m++){
			for(int n=m;n<=N;n++){
				f_min[n][m]=MAXN;
				f_max[n][m]=-MAXN;
				for(int i=m-1;i<=n-1;i++){
					f_min[n][m]=min(f_min[n][m],f_min[i][m-1]*(((prefix[n]-prefix[i])%10+10)%10));
					f_max[n][m]=max(f_max[n][m],f_max[i][m-1]*(((prefix[n]-prefix[i])%10+10)%10));
				}
			}
		}
		
		ansmax=max(ansmax,f_max[N][M]);
		ansmin=min(ansmin,f_min[N][M]);
		//多组ans,求最值 
		
		roll();//环状数组,每算出一次答案都要向前滚动一位
	}
	
	printf("%d\n%d",ansmin,ansmax);
	return 0;
}

7.能量项链

//注意这道题以0开始计数比较方便,不用在意取模的问题

#include<algorithm>
#include<iostream>
#include<fstream>
#include<cstring>
#include<cstdio>
#define MAX 105
using namespace std;

int a[MAX],f[MAX][MAX]={0};

int main(){
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++) scanf("%d",&a[i]);
	
	int ans=0; 
	memset(f,0,sizeof(f));
	for(int d=1;d<n;d++){
		for(int i=0;i<n;i++){
		int j=(i+d)%n;//枚举距离为d的i~j的区间,用取模构成滚动数组 
			for(int k=i;k!=j;k=(k+1)%n){//k为项链的断点,构成不同顺序 
				f[i][j]=max(f[i][j],(f[i][k]+f[(k+1)%n][j])+a[i]*a[(k+1)%n]*a[(j+1)%n]);
				//状转方程:(k之前裂变的能量+k之后的+本次裂变能量)与0取最大值; 
			}
		}
	}
	for(int i=0;i<n;i++) ans=max(f[i][(i-1+n)%n],ans);
	printf("%d",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值