zoukankan      html  css  js  c++  java
  • dp_c_区间dp_g

    You Are The One

    题意:有n个人准备按顺序上台,上台前有个小黑屋(先进后出,即栈),可以被安排进去等待,也可以直接上台,一个人一旦被安排进去,后面的人就可以先上台(小黑屋无限大)。每个人有一个愤怒值angry,如果他是第k个上台的,那么他的怒气和就是(k-1)*angry,如何运用小黑屋安排上台顺序,使得这n个人的怒气总和最小。

    思路:这是一道区间dp题(这几天做的都是区间dp的专题,不是就见鬼了),状态很容易想到,用f[l][r],表示l~rr-l+1个人的最小怒气总和,那么如何转移,其实区间dp大概的套路也就是三个for( for len ; for l,r ; for k (l,r) ),而这题其中的小细节也比较容易观察到,那么问题来了,这也是为什么这题区间dp拿来写的原因,一般的k枚举都是lr来划分区间,但是这题显然没有什么用,为什么没用?因为要用小黑屋啊!如果直接枚举断点,而这题的l, r点是没什么关系的(如果真的有,个人感觉也很难推出,因为每个人的出场顺序其实是不一定的),怎么算出最优?(不用小黑屋也可以看做进去马上出来,问题不大),那么考虑到一个问题,既然出场顺序不一定,那k就枚举出场顺序吧,显然区间l~r的一个人出场顺序就只有r-l+1种,因为如果只有len个人,怎么做到第len+1出场?(一场跑步比赛,你超越了最后一名,你是第几!),至此,转移的for考虑完了,那么这个k来枚举谁呢?第一个?最后一个?随便一个?其实,随便一个都可以,因为最后区间最优,其实顺序是定的,所以先枚举谁都可以,那么就枚举这个区间的第一个吧,因为好写。可以想想,第一个人第k个出场,是不是1~1+k-1比他早出场,1+k~end在他后面出场(所以这些人都多等待了k个人,因而怒气值要多加上k次),那么转移式子就出来了。
    题外:写这题的契机其实有二,一是昨天听同学说了一题区间dp挺有意思的去补了一发,发现自己竟然写出来了dp,说出来是有点开心的,虽然那题并不复杂。而之前一直很害怕dp,觉得能想出来转移的(当然是要能A的正解,瞎想的没有意义)简直就是神仙。最近真的认真思考了一些dp题,发现从简入繁,其实dp挺有意思的,而且个人感觉做dp最大的收益就是很容易看懂别人写的代码(不只是dp的),因为其实dp挺锻炼思维的,一旦开始思考了,理解能力肯定不断地提升。二就是觉得这题区间dp的for套路有意思,k是来枚举顺序的,和别的区间dp(目前自己做到的)不太一样,就放了上来。


    Codes:

    #include <bits/stdc++.h>
    #define pb push_back
    #define de(x) cout << #x << " = " << x << endl
    #define clr(a,b) memset(a,b,sizeof(a))
    using namespace std;
    
    typedef long long ll;
    const int INF = 0x3f3f3f3f;
    const int N = 110;
    
    int f[N][N];
    int a[N], pr[N];
    
    int main()
    {
    	int n;
    	int cas = 1;
    	int t;
    	scanf("%d", &t);
    	while ( t -- )
    	{
    		scanf("%d", &n);
    		pr[0] = 0;
    		for ( int i = 1; i <= n; i ++ )
    		{
    			scanf("%d", &a[i]);
    			pr[i] = pr[i-1] + a[i];
    			f[i][i] = 0;
    		}
    		
    		for ( int len = 2; len <= n; len ++ )
    		{
    			for ( int l = 1, r; ( r = l + len - 1 ) <= n; l ++ )
    			{
    				f[l][r] = INF;
    				for ( int k = 1; k <= len; k ++ )
    				{
    					f[l][r] = min( f[l][r], (k-1)*a[l] + f[l+1][l+k-1] + f[l+k][r] + k*(pr[r]-pr[l+k-1]) );
    				}
    			}
    		}
    		printf("Case #%d: %d
    ", cas++, f[1][n]);	
    	}
    	return 0;
    }
    
  • 相关阅读:
    leetcode701. Insert into a Binary Search Tree
    leetcode 958. Check Completeness of a Binary Tree 判断是否是完全二叉树 、222. Count Complete Tree Nodes
    leetcode 110. Balanced Binary Tree
    leetcode 104. Maximum Depth of Binary Tree 111. Minimum Depth of Binary Tree
    二叉树
    leetcode 124. Binary Tree Maximum Path Sum 、543. Diameter of Binary Tree(直径)
    5. Longest Palindromic Substring
    128. Longest Consecutive Sequence
    Mac OS下Android Studio的Java not found问题,androidfound
    安卓 AsyncHttpClient
  • 原文地址:https://www.cnblogs.com/FormerAutumn/p/9819741.html
Copyright © 2011-2022 走看看