2014-2015 ACM-ICPC, Central Europe Regional Contest (CERC 14) [Gym-100543G]

这篇博客介绍了作者在2014-2015年ACM-ICPC中遇到的一道难题,涉及到区间动态规划(DP)的应用。问题需要将时间离散化,并解决区间选择问题。作者通过反思指出,虽然能推导出最小攻击次数,但未能想到利用区间DP来处理复杂选择情况。

2014-2015 ACM-ICPC, Central Europe Regional Contest (CERC 14)
[Gym-100543G]最后一题,训练完看了别人的代码,发现是区间dp,dp的是时间区间,先要将时间离散化,然后是时间的区间的选择问题,当时就是不知道要怎么组合区间的选择,画图往贪心去想只能推出一个最少要攻击多少次的次数,没有想到可以用区间dp考虑这种麻烦选择。

#include<bits/stdc++.h>
#define time ttt
using namespace std;
const int MAXN = 310;
const int INF = 1e9;
struct SEG
{
    int l,r,c;
    friend bool operator < (const SEG &a,const SEG &b)
    {
        if(a.r!=b.r) return a.r<b.r;
        else return a.l<b.l;
    }
} seg[MAXN];
int dp[MAXN*2][MAXN*2];
int time[MAXN],tot;
int main()
{
    if (fopen("in.txt", "r") != NULL)
    {
        freopen("in.txt", "r", stdin);
        // freopen("out.txt", "w", stdout);
    }
    int t;
    cin>>t;
    seg[0]={0,0,0};
    while(t--)
    {
        int n;
        scanf("%d",&n);
        tot=0;
        for(int i=1; i<=n; i++)
        {
            scanf("%d%d%d",&seg[i].l,&seg[i].r,&seg[i].c);
            time[tot++]=seg[i].l;
            time[tot++]=seg[i].r;
        }
        sort(time,time+tot);
        tot=unique(time,time+tot)-time;
        sort(seg+1,seg+n+1);
        for(int i=1; i<=n; i++)
        {
            seg[i].l=lower_bound(time,time+tot,seg[i].l)-time+1;//把时间离散成了从1开始到tot结束
            seg[i].r=lower_bound(time,time+tot,seg[i].r)-time+1;
        }
        for(int len=2; len<=tot; len++)//枚举时间区间的长度
            for(int i=1; i+len-1<=tot; i++)//起点
            {
                int j=i+len-1;//终点
                int id=0;
                for(int k=1;k<=n;k++)
                {
                    if(seg[k].l>=i&&seg[k].r<=j&&seg[k].c>seg[id].c)//如果满足这个条件的,就意味着这个敌人只能在这个区间中解决掉,不能被dp[i][k-1]或dp[k+1][j]解决
                        id=k;//最强的敌人
                }
                if(id==0)
                    dp[i][j]=0;//如果没有人需要解决就不需要花费,说明已经被小区间给解决了。
                else
                {
                    dp[i][j]=INF;//初始化
                    for(int k=seg[id].l;k<=seg[id].r;++k)
                    {
                        dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]+seg[id].c);//枚举分割点,通过区间dp之前的最优小区间推出大区间
                    }
                }
            }
        printf("%d\n",dp[1][tot]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值