HDU 6365 Shoot Game(区间DP)

15 篇文章 1 订阅

Description

在二维平面有 n n 个障碍物,第i个障碍物为高度 Hi H i 处一段连续区间 [Li,Ri] [ L i , R i ] ,其防御值为 Wi W i ,从原点射击打掉这 N N 个障碍物,每次充能X就可以打掉这条路径上所有防御值不超过 X X 的障碍物,问至少需要多少能量可以消除所有障碍物

Input

第一行一整数T表示用例组数,每组用例首先输入一整数 n n 表示障碍物数量,最后n行每行四个整数 Hi,Li,Ri,Hi H i , L i , R i , H i

(1T10,1n300,1Hi109,109Li,Ri109,0Wi109) ( 1 ≤ T ≤ 10 , 1 ≤ n ≤ 300 , 1 ≤ H i ≤ 10 9 , − 10 9 ≤ L i , R i ≤ 10 9 , 0 ≤ W i ≤ 10 9 )

Output

输出消除所有障碍物所需的最小能量

Sample Input

2
3
1 1 2 2
2 -1 1 4
3 -2 -1 3
3
1 -1 1 2
2 -1 1 3
3 0 2 0

Sample Output

6
3

Solution

显然只用考虑从原点到端点的这 2n 2 n 条射线即可,如果要清除一个从原点开始的扇形区域,那么必然要处理掉防御值最大的那个障碍物,以此可以区间 DP D P 求解

2n 2 n 条射线按极角排序并离散化为 1 1 ~2n,以 dp[l][r] d p [ l ] [ r ] 表示处理掉第 l l 条射线与第r条射线围成区域内所有障碍物所需要最小能量,假设该区间内障碍物的防御值最大为 w[p] w [ p ] ,该障碍物两端的编号为 L[p],R[p] L [ p ] , R [ p ] ,那么有转移

dp[l][r]=min(dp[l][r],dp[l][k1]+dp[k+1][r]+w[p]),L[p]kR[p] d p [ l ] [ r ] = m i n ( d p [ l ] [ r ] , d p [ l ] [ k − 1 ] + d p [ k + 1 ] [ r ] + w [ p ] ) , L [ p ] ≤ k ≤ R [ p ]

时间复杂度 O(n3) O ( n 3 )

Code

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
#define maxn 605
struct node
{
    int x,y;
    node(int _x=0,int _y=0)
    {
        x=_x,y=_y;
    }
    bool operator<(const node&b)const
    {
        return 1ll*x*b.y<1ll*y*b.x;
    }
    bool operator==(const node&b)const
    {
        return 1ll*x*b.y==1ll*y*b.x;
    }
}a[maxn];
int T,n,L[maxn],R[maxn],H[maxn],W[maxn];
ll dp[maxn][maxn];
ll dfs(int l,int r)
{
    if(l>=r)return 0;
    if(dp[l][r]!=1e18)return dp[l][r];
    int p=0;
    for(int i=1;i<=n;i++)
        if(L[i]>=l&&R[i]<=r)
            if(p==0||W[p]<W[i])p=i;
    if(p==0)return dp[l][r]=0;
    for(int k=L[p];k<=R[p];k++)
        dp[l][r]=min(dp[l][r],dfs(l,k-1)+dfs(k+1,r)+W[p]);
    return dp[l][r];
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        int m=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d%d",&H[i],&L[i],&R[i],&W[i]);
            a[m++]=node(L[i],H[i]),a[m++]=node(R[i],H[i]);
        }
        sort(a,a+m);
        m=unique(a,a+m)-a;
        for(int i=1;i<=n;i++)
        {
            L[i]=lower_bound(a,a+m,node(L[i],H[i]))-a+1;
            R[i]=lower_bound(a,a+m,node(R[i],H[i]))-a+1;
        }
        for(int i=1;i<=m;i++)
            for(int j=1;j<=m;j++)
                dp[i][j]=1e18;
        printf("%lld\n",dfs(1,m));
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值