wikioi1085 - 数字游戏(区间DP或者划分DP)

来源:互联网 发布:能帮人找东西的软件 编辑:程序博客网 时间:2024/06/06 05:50

题目链接 WIKIOI1085

【分析】

这题我知道的有两种方法:区间DP和划分DP,其实就是状态定义的不同。由于是环,只要把环打断变成链(扩大一倍)即可,然后每次枚举长度为n的段的起点就可以了,先说区间DP,就是用dp[i][j][m]表示区间i~j内划分成m份的最大价值,用sum[i][j]表示区间i~j中所有数字和%10;状态转移很简单只要把每个区间l~r分成不同的两段,两段最大价值相乘即可,也就是 dp[i][j][m] = max{ dp[i][k][m-1]*sum[k+1][r] };最小值则把max改成min在注意一下初始化就行,但是要注意转移的时候考虑不合法的状态不能转移进去,比如区间1~3如果还要分成4段那么是不可能的,所以不能转移进去。

但是,下载了所有测试数据,这题数据很弱,上面提到的不合法转移测试数据中没有考虑,导致有些程序明明错的也判成对的了

比如

3 3
3
3
3

应该输出

27
27

【AC代码(区间DP)】17ms

#include <cstdio>#include <cstring>#define MAXN 110#define max(a,b) (a>b?a:b)#define min(a,b) (a<b?a:b)int a[MAXN], dp[MAXN][MAXN][10], sum[MAXN][MAXN], n;int dfs(int l, int r, int m){int& ans = dp[l][r][m];if(~ans) return ans;if (1 == m || l >= r)return ans = sum[l][r];ans = 0;for (int k = m+l-2; k < r; k++)//r-l+1-m>=1 ==> r >= m+l-2防止区间l~r内个数小于划分数导致不合法sum[k+1][r]乘进去 ans = max(ans,dfs(l,k,m-1)*sum[k+1][r]);return ans;}int dfs2(int l, int r, int m){int& ans = dp[l][r][m];if(~ans) return ans;if (1 == m || l >= r)return ans = sum[l][r];ans = 0x3f3f3f3f;for (int k = m+l-2; k < r; k++)ans = min(ans,dfs(l,k,m-1)*sum[k+1][r]);return ans;}int main(){#ifdef SHYfreopen("e:\\1.txt","r",stdin);#endifint m;scanf("%d %d%*c", &n, &m);for (int i = 0; i < n; i++)scanf("%d%*c", &a[i]), a[i+n] = a[i];memset(sum,0,sizeof(sum));for (int i = 0; i < (n<<1); i++){for (int j = i; j < (n<<1) && j < i+n; j++){if (j)sum[i][j] = sum[i][j-1];sum[i][j] = ((sum[i][j]+a[j])%10+10)%10;}}int ans = 0x3f3f3f3f;memset(dp,-1,sizeof(dp));for (int i = 0; i < n; i++)ans = min(ans,dfs2(i,i+n-1,m));printf("%d\n", ans);ans = 0;memset(dp,-1,sizeof(dp));for (int i = 0; i < n; i++)ans = max(ans,dfs(i,i+n-1,m));printf("%d\n", ans);return 0;}



再说另外一种方法:其实上面的L始终为0,可以把状态定义成为dp[r][m]表示区间1~r划分成m份的最大价值,这样就可以把转移方程改为dp[r][m] = max{ dp[k][m-1]*sum[k+1][r] };

还是枚举长度为n的段。不需要担心不合法状态了。由于状态中始终是从1开始的,所以需要每次计算sum[][]还有初始化dp[][]。这样其实只是降低了空间复杂度,时间复杂度是一样的

 

【AC代码(改进后)】15ms

#include <cstdio>#include <cstring>#define MAXN 52#define max(a,b) (a>b?a:b)#define min(a,b) (a<b?a:b)int a[MAXN*2], dp[MAXN][10], sum[MAXN][MAXN], n;int dfs(int r, int m){int& ans = dp[r][m];if(~ans) return ans;if (1 == m) return ans = sum[1][r];ans = 0;for (int k = 1; k < r; k++)ans = max(ans,dfs(k,m-1)*sum[k+1][r]);return ans;}int dfs2(int r, int m){int& ans = dp[r][m];if(~ans) return ans;if (1 == m) return ans = sum[1][r];ans = 0x3f3f3f;for (int k = 1; k < r; k++)ans = min(ans,dfs2(k,m-1)*sum[k+1][r]);return ans;}void c_sum(int x)//计算x~x+n的sum[][]{for (int i = 1; i <= n; i++){for (int j = i; j <= n; j++)sum[i][j] = ((sum[i][j-1]+a[j+x-1])%10+10)%10;}}int main(){#ifdef SHYfreopen("e:\\1.txt","r",stdin);#endifint m;scanf("%d %d%*c", &n, &m);for (int i = 1; i <= n; i++)scanf("%d%*c", &a[i]), a[i+n] = a[i];int ans = 0x3f3f3f3f;for (int i = 1; i <= n; i++){c_sum(i);memset(dp,-1,sizeof(dp));ans = min(ans,dfs2(n,m));}printf("%d\n", ans);ans = 0;for (int i = 1; i <= n; i++){c_sum(i);memset(dp,-1,sizeof(dp));ans = max(ans,dfs(n,m));}printf("%d\n", ans);return 0;}


 

 

 

0 0
原创粉丝点击