!HDU 4283 屌丝联谊会-区间dp

题意:一群屌丝排队参加联谊,每个人都有屌丝值,如果他是第k个进场的,那么他的愤怒值就是(K-1)*Di,主办方想使所有屌丝的愤怒值总和最小,就用一个黑屋子来改变屌丝的进场顺序,黑屋子实际上是一个栈,先进后出。现在要求用这个栈能得到的最小的愤怒值总和是多少。

分析:

难点在于你不知道用了多少次黑屋子、用在哪些人身上以及每次各自进黑屋子的人数。很容易知道每个决策都会影响最终结果,那么我们就想用dp来做。问题是哪种dp,本题实际上就是在区间上求最优解,所以用区间dp。区间dp就是每次把一个区间分成两个区间,然后这两个局部区间的最优解合并得到这个大区间的最优解。

状态:dp[i][j]表示第i个人到第j个人这段区间的他们以各种方式使用黑屋子得到的最小的愤怒值;

转移:dp[i][j]=min(dp[i][j],a[i]*(k-1)+dp[i+1][i+k-1]+dp[i+k][j]+k*(sum[j]-sum[i+k-1]))

转移方程是这样得到的:在区间[i~j]中,考虑第一个也就是第i个人的进场顺序设为k。第一个进场不用说,如果他第二个进场,那么第一个进场的肯定是他后面的那个人,也就是第i+1个人,以此类推,如果他第k个进场,那么他后面的连续k-1个人一定比他先进场,不过这k-1个人的顺序又是一个子问题了,这也是用到dp的地方。

三重循环枚举区间的起点终点和k。

区间dp不太懂,以后继续积累。

代码:

#include<cstdio>
#include<cstring>
#define min(a,b) a<b?a:b
#define INF 1000000007
int dp[105][105];
int t,n,a[105];
int sum[105];
int main()
{
	scanf("%d",&t);
	for(int cas=1;cas<=t;cas++){
		scanf("%d",&n);
		for(int i=0;i<n;i++) sum[i]=0;
		scanf("%d",&a[0]);
		sum[0]=a[0];
		for(int i=1;i<n;i++){
			scanf("%d",&a[i]);
			sum[i]=sum[i-1]+a[i];
		}
		memset(dp,0,sizeof(dp));
		for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) dp[i][j]=INF;
		for(int l=1;l<n;l++){
			for(int i=0;i<=n-l;i++){
				int j=i+l;
				for(int k=1;k<=j-i+1;k++){
					dp[i][j]=min(dp[i][j],a[i]*(k-1)+dp[i+1][i+k-1]+dp[i+k][j]+k*(sum[j]-sum[i+k-1]));
				}
		    }

		}
		printf("Case #%d: %d\n",cas,dp[0][n-1]);
	}
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-25 21:03:19

!HDU 4283 屌丝联谊会-区间dp的相关文章

HDU 4632 Palindrome subsequence(区间dp,回文串,字符处理)

题目 参考自博客:http://blog.csdn.net/u011498819/article/details/38356675 题意:查找这样的子回文字符串(未必连续,但是有从左向右的顺序)个数. 简单的区间dp,哎,以为很神奇的东西,其实也是dp,只是参数改为区间,没做过此类型的题,想不到用dp,以后就 知道了,若已经知道[0,i],推[0,i+1], 显然还要从i+1 处往回找,dp方程也简单: dp[j][i]=(dp[j+1][i]+dp[j][i-1]+10007-dp[j+1][

HDU 5396 Expression (区间DP)

链接 : http://acm.hdu.edu.cn/showproblem.php?pid=5396 设d[i][j] 代表i~j的答案.区间DP枚举(i, j)区间的断点,如果断点处的操作符是'*',那么该区间的答案可以直接加上d[i][k] *  d[k+1][j],因为乘法分配律可以保证所有的答案都会乘起来.如果是加法,需要加的 就是 左边的答案 乘 右边操作数的阶乘 加上 右边的答案乘左边操作数的阶乘,最后要确定左边操作和右边操作的顺序 因为每个答案里是统计了该区间所有的阶乘情况,因此

hdu 5693 &amp;&amp; LightOj 1422 区间DP

hdu 5693 题目链接http://acm.hdu.edu.cn/showproblem.php?pid=5693 等差数列当划分细了后只用比较2个或者3个数就可以了,因为大于3的数都可以由2和3组合成. 区间DP,用dp[i][j]表示在i到j之间可以删除的最大数,枚举区间长度,再考虑区间两端是否满足等差数列(这是考虑两个数的),再i到j之间枚举k,分别判断左端点右端点和k是否构成等差数列(还是考虑两个数的),判断左端点,k,右端点是否构成等差数列(这是老驴三个数的) 1 #include

hdu 4597 Play Game 区间dp

Play Game Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4597 Description Alice and Bob are playing a game. There are two piles of cards. There are N cards in each pile, and each card has a score. They take tur

hdu 5181 numbers——思路+区间DP

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5181 题解:https://www.cnblogs.com/Miracevin/p/10960717.html 原来卡特兰数的这个问题还能区间DP…… XO #include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; int rdn() { in

hdu 4570 Multi-bit Trie 区间DP入门

Multi-bit Trie 题意:将长度为n(n <= 64)的序列分成若干段,每段的数字个数不超过20,且每段的内存定义为段首的值乘以2^(段的长度):问这段序列总的内存最小为多少? 思路:区间的最值,区间DP; 枚举长度,在初始化时,将长度和20比较,小于20看成是一段,大于20时,因为不能压缩,直接全部分割就是了:之后枚举区间内部的所有值,这是并不需要考虑将这个区间一分为二后各自的长度是否大于20,因为在子结构中已经计算好了:直接去最优解即可: #include<iostream>

hdu 4412 Sky Soldiers(区间DP)

Sky Soldiers Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 559    Accepted Submission(s): 181 Problem Description An airplane carried k soldiers with parachute is plan to let these soldiers j

hdu 6049---Sdjpx Is Happy(区间DP+枚举)

题目链接 Problem Description Sdjpx is a powful man,he controls a big country.There are n soldiers numbered 1~n(1<=n<=3000).But there is a big problem for him.He wants soldiers sorted in increasing order.He find a way to sort,but there three rules to obe

【DP】 HDU 5115 Dire Wolf 区间DP

点击打开链接 题意:一头狼的攻击力= 自己攻击力+相邻两边的狼的加成 每杀一头狼会收到一次攻击 求受到的攻击和最小 比较裸的区间DP #include <cstdio> #include <cstring> #include <cstdlib> #include <string> #include <iostream> #include <algorithm> #include <sstream> #include <