版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/V5ZSQ/article/details/82562802
Description
在二维平面有 个障碍物,第 个障碍物为高度 处一段连续区间 ,其防御值为 ,从原点射击打掉这 个障碍物,每次充能 就可以打掉这条路径上所有防御值不超过 的障碍物,问至少需要多少能量可以消除所有障碍物
Input
第一行一整数 表示用例组数,每组用例首先输入一整数 表示障碍物数量,最后 行每行四个整数
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
显然只用考虑从原点到端点的这 条射线即可,如果要清除一个从原点开始的扇形区域,那么必然要处理掉防御值最大的那个障碍物,以此可以区间 求解
将 条射线按极角排序并离散化为 ~ ,以 表示处理掉第 条射线与第 条射线围成区域内所有障碍物所需要最小能量,假设该区间内障碍物的防御值最大为 ,该障碍物两端的编号为 ,那么有转移
时间复杂度
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;
}