区间DP基础篇之 HDU4283——You Are the One(非诚勿扰)

题目大意:

有n个男屌丝事先按1,2,3,,,,,,n的顺序排好,每个人都有一个不开心值unhappy[i],如果第i个人第k个上台找对象,那么该屌丝男的不开心值就会为(k-1)*unhappy[i],因为在他前面有k-1个人嘛,导演为了让所有男屌的总不开心值最小,搞了一个小黑屋,可以通过小黑屋来改变男屌的出场顺序

注意:这个小黑屋是个栈,男屌的顺序是排好了的,但是可以通过入栈出栈来改变男屌的出场顺序

解题思路:(操度娘所知~度娘你好腻害)

dp[i][j]表示区间[i,j]的最小总不开心值

把区间[i,j]单独来看,则第i个人可以是第一个出场,也可以是最后一个出场(j-i+1),也可以是在中间出场(1   ~  j-i+1)

不妨设他是第k个出场的(1<=k<=j-i+1),那么根据栈后进先出的特点,以及题目要求原先男的是排好序的,那么::

第  i+1  到 i+k-1  总共有k-1个人要比i先出栈,

第 i+k   到j 总共j-i-k+1个人在i后面出栈

举个例子吧:

有5个人事先排好顺序  1,2,3,4,5

入栈的时候,1入完2入,2入完3入,如果我要第1个人第3个出场,那么入栈出栈顺序是这样的:

1入,2入,3入,3出,2出,1出(到此第一个人就是第3个出场啦,很明显第2,3号人要在1先出,而4,5要在1后出)

这样子,动态转移方程就出来啦,根据第i个人是第k个出场的,将区间[i,j]分成3个部分

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

(sum[j]-sum[i+k-1])*k 表示 后面的 j-i-k+1个人是在i后面才出场的,那么每个人的不开心值都会加个 unhappy,sum[i]用来记录前面i个人的总不开心值,根据题目,每个人的unhappy是个累加的过程,多等一个人,就多累加一次

—————————————————————————————————分割线———————————————————————————————

贴代码咯,好开心啊,敲了好久,终于把思路敲完了:

记忆化搜索 15MS

<span style="font-size:18px;">#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int dp[110][110];
int a[110],sum[110];
int n;
int solve(int i,int j)
{
    int &ans=dp[i][j];
    if(ans!=-1) return ans;
    if(i>=j) return 0;
    ans=1<<30;
    for(int k=1;k<=j-i+1;k++){
        ans=min(ans,solve(i+1,i+k-1)+solve(i+k,j)+(k-1)*a[i]+(sum[j]-sum[i+k-1])*k);
    }
    return ans;
}
int main()
{
    int t,iCase=1;
    cin>>t;
    while(t--){
        cin>>n;
        sum[0]=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            sum[i]=sum[i-1]+a[i];
        }
        memset(dp,-1,sizeof dp);
        printf("Case #%d: %d\n",iCase++,solve(1,n));
    }
    return 0;
}</span>

递推式 0MS

<span style="font-size:18px;">#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define maxn 110
#define inf 0x7fffffff
using namespace std;
int dp[maxn][maxn];
int sum[maxn];
int a[maxn];
int n;
int main()
{
    int t,iCase=1;
    scanf("%d",&t);
    while(t--){
        sum[0]=0;
        scanf("%d",&n);
        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=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                dp[i][j]=inf;
            }
        }
        for(int p=1;p<=n;p++){
            for(int i=1;i<=n-p+1;i++){
                int j=i+p-1;
                for(int k=1;k<=p;k++){
                    dp[i][j]=min(dp[i][j],dp[i+1][i+k-1]+dp[i+k][j]+(k-1)*a[i]+(sum[j]-sum[i+k-1])*k);
                }
            }
        }
        printf("Case #%d: %d\n",iCase++,dp[1][n]);
    }
    return 0;
}</span>

区间DP基础篇之 HDU4283——You Are the One(非诚勿扰)

时间: 2024-10-17 02:19:19

区间DP基础篇之 HDU4283——You Are the One(非诚勿扰)的相关文章

区间DP基础篇之 POJ2955——Brackets

怒拿一血,first blood,第一个区间DP,第一次就这样子莫名其妙不知不觉滴没了~~~ 题目虽然是鸟语,但还是很赤裸裸的告诉我们要求最大的括号匹配数,DP走起~ dp[i][j]表示区间[i,j]的最大匹配数,那么最重要的状态转移方程就是: dp[i][j]=max(dp[i][k]+dp[k+1][j]) 对啦,要先初始化边界啊,两步走~: memset(dp,0,sizeof dp); if str[i]==str[i+1]   则:dp[i][i+1]=2       请看---->

区间DP基础篇之 POJ1159——Palindrome

题目大意:给定一个字符串,求最少插入几个字符让该字符串成为回文串 法一: dp[i][j]表示使区间[i,j]成为回文串最小插入的字符数,则状态转移方程 1.if s[i]==s[len-1] 则:d[i][j]=d[i+1][j-1] 2.else  d[i]=min(dp[i+1][j],dp[i][j-1]) 首尾字符不同的时候,有两种决策. 1.将新字符插在首位,那么状态就变成了dp[i+1][j]了. 2.将新字符插在末尾,则状态就变成了dp[i][j-1]了 .比较两种决策哪种更优就

区间DP基础——石子归并

http://acm.nyist.net/JudgeOnline/problem.php?pid=737 石子归并:先枚举要合并的区间长,然后枚举相应的区间左端点,最后枚举区间中间的划分点,这样,就可以由小到大递推解决区间问题了. 转移方程:dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]) 1 #include<iostream> 2 #include<cstdio> 3 #define INF

Light OJ 1422 Halloween Costumes 区间DP基础题

Halloween Costumes 题目链接: http://lightoj.com/volume_showproblem.php?problem=1422 题意: Gappu想要去参加一些party,他去每个party都要把特定编号的服装穿在外边,他可以穿上或者脱掉服装(脱掉的服装不能再穿一次,但是可以穿一件相同编号新的服装,最近穿的服装会套在之前穿的服装的外边),问Gappu最少需要准备多少套服装. 题解: 设dp[i][j]为区间 i 到 j (设len为区间长度,j=i+len)内最少

POJ 2955:Brackets 区间DP基础题

Brackets 题目链接: http://poj.org/problem?id=2955 题意: 给出一个只由'('.')'.'['.']'构成的字符串,字符间可以匹配,左边的 '(' 可以与右边的 ')' 匹配,左边的 '[' 可以与右边的 ']' 匹配 两种匹配不能交叉,可以包含,如 [(])只算2个匹配而[()]算四个匹配,求最大匹配数. 题解: 设dp[i][j]为区间 i 到 j (设len为区间长度,j=i+len)内可以得到的最大匹配数,则有两种情况: ① j 不与区间[i,j]

hdu4283(区间dp)

You Are the One Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1585    Accepted Submission(s): 756 Problem Description The TV shows such as You Are the One has been very popular. In order to me

HDU4283:You Are the One(区间DP)

Problem Description The TV shows such as You Are the One has been very popular. In order to meet the need of boys who are still single, TJUT hold the show itself. The show is hold in the Small hall, so it attract a lot of boys and girls. Now there ar

HDU-4283 You Are the One (区间DP)

Problem Description The TV shows such as You Are the One has been very popular. In order to meet the need of boys who are still single, TJUT hold the show itself. The show is hold in the Small hall, so it attract a lot of boys and girls. Now there ar

石子合并问题(一) (基础的区间dp)

石子合并(一) 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述     有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆.求出总的代价最小值. 输入 有多组测试数据,输入到文件结束. 每组测试数据第一行有一个整数n,表示有n堆石子. 接下来的一行有n(0< n <200)个数,分别表示这n堆石子的数目,用空格隔开 输出 输出总代价的最小值,