[机房练习赛4.7] 碰杯 区间DP

碰杯(toasting.in/toasting.out)

今天的酒席有n个人,他们要同时举杯,成对碰杯。碰杯的时候,不能有人不参与碰杯,也不希望有手臂交叉这种别扭的情况出现。如下图,左图的情况是好的,右图的情况是不希望出现的。
每个人都有一个喜爱的酒种类,每个人想要与和自己喝一样酒的人碰杯,请你设计一个方法,在保证每个人参与碰杯,且没有手臂交叉的情况下,有最多的人与喝一样酒的人碰杯,输出最多有多少人能与喝一样酒的人碰杯。
【输入格式】
第一行一个数n,表示酒桌上人的个数。
第二行n个数ci,逆时针方向依次表示坐在第i个位置的人喝哪种酒,第1个和第n个人是相邻的。
【输出格式】
一个整数,表示在保证每个人参与碰杯,且没有手臂交叉的情况下,最多有多少人能与喝一样酒的人碰杯。
【输入样例1】
6
1 2 2 1 3 3
【输出样例1】
3
【数据规模】
10% 数据满足2≤n≤10。
100% 数据满足2≤n≤1000,1≤ci≤100。
【解法】
区间dp。
设dp[i][j] 表示从i到j的人,在没有交叉的时候的最优解。
则从小到大枚举(j-i+1),并且保证j-i为奇数(否则不能保证i到j所有人参与碰杯)。
3
设s,t为当前的l和r。
dp[s][t] = dp[s + 1][t - 1] + (a[s] == a[t]);(s与t碰杯)
for(int k = s + 1; k < t; k += 2) (k为切割点,s与k碰杯,k+1与t碰杯)
dp[s][t] = max(dp[s][t], dp[s][k] + dp[k+1][t]);

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1000 + 5;
int dp[N][N],a[N];
int main(){
    freopen("toasting.in","r",stdin);
    freopen("toasting.out","w",stdout);
    int n;
    scanf("%d", &n);
    for( register int i = 1;i <= n; i++ ) scanf("%d", &a[i]);
    for( register int i = 2; i <= n; i++ )
        for( register int j = i-1; j > 0; j -= 2 )
            for( register int k = j; k < i; k += 2 ){
                int ans = 0;
                if( a[i] == a[k] ) ans = 1;
                dp[j][i] = max(dp[j][i],dp[j][k-1] + dp[k+1][i-1] + ans);
            }
    printf("%d", dp[1][n]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值