hdu 6365 Shoot Game 区间dp

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ccsu_cat/article/details/81539498

多校六第四题,比赛没看这题,并且看了也一定不会写...看了标程和思路后,发现也没那么难,主要还是dp练的太少,题意是给出n个高度为H,左端点和右端点分别为L R,以及血量为W的怪物,你要用激光消灭所有的怪物,消耗值为 x 的的激光可以扣怪物 x 的血量,并且当怪物死了后,该次激光就会穿怪物并透射向后面的怪物。求用最少的激光值消灭所有怪物。

思路:因为怪物死了激光可以穿透,那么某一个区间内,肯定优先杀血量最多的怪物,这样就可以一条射线消灭该射线接触的所有怪物,这个题有点麻烦就是给出的高度以及左端点右端点数值太大,所以需要根据斜率离散化,把所有端点根据斜率排序,设dp[ l ][ r ]为消灭区间 l  r 所有怪物所需的最少的激光值,首先找到区间l r 血量最多的怪物x,设怪物x 的血量为Max,左端点为s,右端点为e,那么转移方程肯定就是dp[ l ][ r ]=min(dp[ l ][ k-1 ]+dp[ k+1 ][ r ]+Max), k 属于区间[ s , e ]。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
typedef long long LL;
const int maxn=605;
const LL inf=1e18;
struct P
{
	LL x,y;
	bool operator==(const P& rhs)const
	{
		return x*rhs.y==y*rhs.x;
	}
	bool operator<(const P& rhs)const
	{
		return x*rhs.y<y*rhs.x;
	}
}p[maxn];
LL H[maxn],L[maxn],R[maxn],W[maxn];
LL dp[maxn][maxn];
int Li[maxn],Ri[maxn],n,hn;
int find(P x)
{
	return lower_bound(p+1,p+1+hn,x)-p;
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%lld%lld%lld%lld",&H[i],&L[i],&R[i],&W[i]);
			p[i*2-1]=(P){L[i],H[i]};
			p[i*2]=(P){R[i],H[i]};
		}
		sort(p+1,p+1+n*2);
		hn=unique(p+1,p+1+n*2)-p-1;
		for(int i=1;i<=n;i++)
		{
			Li[i]=find((P){L[i],H[i]});
			Ri[i]=find((P){R[i],H[i]});
		}
		for(int len=1;len<=hn;len++)
		for(int l=1;l+len-1<=hn;l++)
		{
			int r=l+len-1;
			dp[l][r]=inf;
			int Max=-1,cur=0;
			for(int i=1;i<=n;i++)
			if(Li[i]>=l&&Ri[i]<=r&&W[i]>Max)
			Max=W[i],cur=i;
			if(Max==-1)dp[l][r]=0;
			else
			{
				int s=Li[cur],e=Ri[cur];
				for(int i=s;i<=e;i++)
				dp[l][r]=min(dp[l][r],dp[l][i-1]+dp[i+1][r]+Max);
			}
		}
		printf("%lld\n",dp[1][hn]);
	}
}

猜你喜欢

转载自blog.csdn.net/ccsu_cat/article/details/81539498