zstu2552---马棚问题 DP
题目来源:http://acmpj.zstu.edu.cn/JudgeOnline/showproblem?problem_id=2552
动态规划基本步骤(本人觉得):
1.确定数组的维数,一维,二维等等;2.弄清数组下标的含义3.找出状态转移方程式;4实现自己的想法;
本题思路:
二维数组dp[i][j],i表示前i个马棚放马完毕,j表示队列前j匹马已经进入马棚,dp[i][j]记录前j匹马放在前i个马棚里的最小不愉快系数,用f(a,b)表示只把第a匹马到第b匹马放在一个马棚里的不愉快系数;
思考得出 状态转移方程:dp[i][j]=min(dp[i-1][t]+f(t,j));注意范围:(i-1<=t<j),(i<=j<=n-(n-k))
范围得出的理由:每个马棚都至少要放一匹马;
用zero[j],one[j]两个数组记录前j匹马中黑白马的个数;
则不难得出 f(a,b)=(zero[b]-zero[a])*(one[b]-one[a]);
View Code
#include<stdio.h> int dp[501][501],zero[501],one[501]; int main() { int n,k,i,j,t,x; while(scanf("%d%d",&n,&k)!=EOF) { zero[0]=one[0]=0; for(i=1;i<=n;i++) { scanf("%d",&x); if(x){zero[i]=zero[i-1];one[i]=one[i-1]+1;} else {zero[i]=zero[i-1]+1;one[i]=one[i-1];} } dp[1][1]=0; for(j=2;j<=n-k+1;j++) dp[1][j]=one[j]*zero[j]; for(i=2;i<=k;i++) { for(j=i;j<=n-(k-i);j++) { int min=999999; for(t=i-1;t<j;t++) { int temp=(one[j]-one[t])*(zero[j]-zero[t]); if(dp[i-1][t]+temp<min)min=dp[i-1][t]+temp; } dp[i][j]=min; } } printf("%d\n",dp[k][n]); } return 0; }
做完一道题后,再看看别人的做法,发现可以用一维数组,结果又写了个一维数组,思想是完全一样的,
只是用了dp[j],省去i;
理由:在递推过程中有些数据用一次就没什么用了,用了一维数组正是用了这个规律,
自己打个二维的dp[i][j],模拟一下计算过程就知道为什么可以用一维数组了;
View Code
#include<stdio.h> int zero[550],one[550]; int dp[505]; int main() { int n,k,a,i,j,t,x,temp,min; while(scanf("%d%d",&n,&k)!=EOF) { zero[0]=one[0]=0; for(i=1;i<=n;i++) { scanf("%d",&x); if(x){one[i]=one[i-1]+1;zero[i]=zero[i-1];} else {one[i]=one[i-1];zero[i]=zero[i-1]+1;} } for(j=1;j<=n;++j) { dp[j]=zero[j]*one[j]; } for(i=2;i<=k;i++) { for(j=n-(k-i);j>=1;j--) //思考为什么从大到小 { min=999999; for(t=i-1;t<j;t++) { int temp=(one[j]-one[t])*(zero[j]-zero[t]); if(dp[t]+temp<min)min=dp[t]+temp; } dp[j]=min; } } printf("%d\n",dp[n]); } return 0; }


浙公网安备 33010602011771号