HDU 4283 You Are the One(区间dp)
来源:互联网 发布:java颗粒度是什么意思 编辑:程序博客网 时间:2024/06/05 09:29
//区间dp的用法真是灵活
//这个题 想了很长时间 还是错了
//下面的思路是参照大牛ZeroClock的
// 思路: 栈有一个重要的性质就是 假设共有[1,n]元素 如果第一个元素第k个出栈则 元素2到k比第一个元素先出栈 元素k+1到n比第一个元素后出栈
// 那么[1,n]就被分成了[2,k] [k+1,n]两个区间这样就可以用区间dp的三重循环的去做了
//第一重循环i表示区间的起点 第二重循环j表示区间的终点 第三重循环k表示区间[i,j]的第一个元素i 第k个出栈
// 则 dp[i][j]=dp[i+1][k]+dp[k+1][j]+s;
// s为当前选择对后续的影响 应该提前加到当前的状态了
#include<stdio.h>
#include<string.h>
#define N 105
#define inf 99999999
int dp[N][N];
int a[N], sum[N];
int min(int a,int b){return a<b?a:b;}
void init(int n)
{
int i ,j;
memset(sum,0,sizeof(sum));
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)//因为j<i是非法状态所以值为0
{
dp[i][j]=inf;
}
}
int solve_dp(int n)
{
int i,j,k,s; //dp[i][j]表示的是只要区间[i,j]时最佳出栈方式的总屌丝值
for(i=n;i>=1;i--)//枚举区间起点
{
for(j=i;j<=n;j++)//枚举区间终点
{
for(k=i;k<=j;k++)//枚举元素i是第k个出栈
{
if(i==j)continue;
s=a[i]*(k-i);
s+=dp[i+1][k]+dp[k+1][j];
s+=(k-i+1)*(sum[j]-sum[k]);
dp[i][j]=min(dp[i][j],s);
}
}
}
return dp[1][n];
}
int main()
{
int t,n,X=1;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
init(n);
int ans=solve_dp(n);
printf("Case #%d: %d\n",X++,ans);
}
return 0;
//这个题 想了很长时间 还是错了
//下面的思路是参照大牛ZeroClock的
// 思路: 栈有一个重要的性质就是 假设共有[1,n]元素 如果第一个元素第k个出栈则 元素2到k比第一个元素先出栈 元素k+1到n比第一个元素后出栈
// 那么[1,n]就被分成了[2,k] [k+1,n]两个区间这样就可以用区间dp的三重循环的去做了
//第一重循环i表示区间的起点 第二重循环j表示区间的终点 第三重循环k表示区间[i,j]的第一个元素i 第k个出栈
// 则 dp[i][j]=dp[i+1][k]+dp[k+1][j]+s;
// s为当前选择对后续的影响 应该提前加到当前的状态了
#include<stdio.h>
#include<string.h>
#define N 105
#define inf 99999999
int dp[N][N];
int a[N], sum[N];
int min(int a,int b){return a<b?a:b;}
void init(int n)
{
int i ,j;
memset(sum,0,sizeof(sum));
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)//因为j<i是非法状态所以值为0
{
dp[i][j]=inf;
}
}
int solve_dp(int n)
{
int i,j,k,s; //dp[i][j]表示的是只要区间[i,j]时最佳出栈方式的总屌丝值
for(i=n;i>=1;i--)//枚举区间起点
{
for(j=i;j<=n;j++)//枚举区间终点
{
for(k=i;k<=j;k++)//枚举元素i是第k个出栈
{
if(i==j)continue;
s=a[i]*(k-i);
s+=dp[i+1][k]+dp[k+1][j];
s+=(k-i+1)*(sum[j]-sum[k]);
dp[i][j]=min(dp[i][j],s);
}
}
}
return dp[1][n];
}
int main()
{
int t,n,X=1;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
init(n);
int ans=solve_dp(n);
printf("Case #%d: %d\n",X++,ans);
}
return 0;
}
记忆化搜索方法(转自ZeroClock)始终没看懂!
本题的模型是求一个合法的出栈序列使得屌丝总值最小,需要用区间DP解决之。合法的出栈序列中有一个很重要的性质:[1,n]这是一开始的所有元素,当1第k个出栈时[2,k]肯定比1先出栈,[k+1,n]肯定比1后出栈,正因为只要1才能第k个出栈.。这样一个区间划分成两个子区间[2,k],[k+1,n],就这样递归下去只到区间长度为1.而区间DP正是解决这类区间划分问题的利器,其实区间DP也就是一种思想啦。
- #include <stdio.h>
- #include <string.h>
- #define MAX 104
- #define INF (1<<29)
- #define min(a,b) ((a)<(b)?(a):(b))
- int n,ans,arr[MAX];
- int dp[MAX][MAX][MAX];
- int Solve_DP(int s,int e,int k) {
- //s是区间头,e是区间尾,k表示第i个人第k个出栈
- if (s == e) return arr[s] * (k - 1);
- if (s > e) return 0;
- if (dp[s][e][k] != INF) return dp[s][e][k];
- int i,first,second;
- int cur,thisk,nextk;
- for (i = s; i <= e; ++i) { //区间分成两部分,[s,i]和[i+1,e]
- nextk = k + (i - s) + 1; //[i+1,e]区间内第i个人第nextk个出栈
- thisk = k + (i - s); //[s,i]区间的第s个人第thisk个出栈
- first = Solve_DP(s+1,i,k); //第1个区间经过分配得到最少屌丝值
- second = Solve_DP(i+1,e,nextk); //第2个区间经过分配得到的最少屌丝值
- cur = arr[s] * (thisk - 1); //第s个人第thisk出栈增加的屌丝值
- dp[s][e][k] = min(dp[s][e][k],first+second+cur);
- }
- return dp[s][e][k];
- }
- int main()
- {
- int i,j,k,t,cas = 0;
- scanf("%d",&t);
- while (t--) {
- scanf("%d",&n);
- for (i = 1; i <= n; ++i)
- scanf("%d",&arr[i]);
- for (i = 1; i <= n; ++i)
- for (j = 1; j <= n; ++j)
- for (k = 0; k < n; ++k)
- dp[i][j][k] = INF;
- ans = Solve_DP(1,n,1);
- printf("Case #%d: %d\n",++cas,ans);
- }
- }
0 0
- HDU 4283 You Are the One 区间dp
- hdu 4283 You Are the One 区间dp
- HDU 4283 You Are the One(区间DP)
- hdu 4283 You Are the One(区间dp)
- HDU --4283--You Are the One--区间DP
- hdu 4283 You Are the One(区间DP)
- HDU 4283 You Are the One(区间dp)
- HDU 4283 You Are the One 区间dp
- HDU 4283 You Are the One (区间DP)
- HDU 4283 You Are the One(区间dp)
- hdu 4283 You Are the One(区间dp)
- Hdu 4283 You Are the One(区间dp)
- HDU 4283 You are the one(区间DP)
- HDU 4283 You Are the One(区间DP)
- HDU 4283 You Are the One (区间dp)
- HDU 4283 You Are the One(区间dp)
- hdu 4283 You are the one 区间dp
- HDU 4283 You Are the One (区间DP)
- java 的堆栈
- Linux rpm 命令参数使用详解[介绍和应用]
- MFC中窗口的销毁过程
- Android 4.0调用http接口php网站的api
- glibc 内存池管理 ptmalloc(转)
- HDU 4283 You Are the One(区间dp)
- 让你提前认识软件开发(3):学校C语言教材的缺陷
- 让Python脚本暂停执行的几种方法
- 三个水杯_ny_21(广搜).java
- 简单工厂VS工厂方法
- glibc内存管理 (转)
- 程序员的奋斗史(三十六)——人在囧途之应聘篇(六)——第一季终结篇
- struts2请求流程
- hdu 2545 并查集 树上战争