HDU6365 Shoot Game

考完以后听说是中期题区间DP?我考场上竟然没去看?然而时隔一周我发现我这题还没有补掉,于是今天乘着没有可做题补来看一蛤,结果就是1个小时毫无思路,根本不知道区间怎么设定,讲道理要按极角排序的,然而因为一条线段有两个点,所以他极角排序的可能是相隔的,那dp[i][j]表示i到j个点被覆盖的最小值?有些线段在i-j中间,有些只有1个点在中间怎么办?于是乎哀我太菜,看波题解,原来题解的表示方法是dp[i][j]表示i到j的极角区间中2个点都在里面的线段被覆盖的条件,那么这个区间中最大的线段是一定加入花费中的,那么就枚举这个线段两个端点的中间的位置,区间最优值合并一蛤,就能表示这个最大线段不摧毁的情况时加上被摧毁的花费

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxl 666

using namespace std;

int n,tot,cnt;
struct node
{
	int x,y,id;bool isl;
	node(){}
	node(int x,int y,bool isl,int id):x(x),y(y),isl(isl),id(id){};
	bool operator != (const node &b) const
	{
		return 1ll*x*b.y-1ll*b.x*y!=0;
	}
	bool operator <(const node &b) const
	{
		return 1ll*b.y*x-1ll*b.x*y<0;
	}
}a[maxl];
int l[maxl],r[maxl],w[maxl],h[maxl];
long long f[maxl][maxl];

inline void prework()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d%d%d",&h[i],&l[i],&r[i],&w[i]);
		a[i*2-1]=node(l[i],h[i],true,i);
		a[i<<1]=node(r[i],h[i],false,i);
	}
	sort(a+1,a+1+2*n);
	cnt=1;
	if(a[1].isl)
		l[a[1].id]=1;
	else
		r[a[1].id]=1;
	for(int i=2;i<=2*n;i++)
	{
		if(a[i]!=a[i-1])
			cnt++;
		if(a[i].isl)
			l[a[i].id]=cnt;
		else
			r[a[i].id]=cnt;
	}
}

inline void mainwork()
{
	int j;
	for(int len=1;len<=cnt;len++)
		for(int i=1;i+len-1<=cnt;i++)
		{
			j=i+len-1;
			int mx=-1,mxind;
			for(int k=1;k<=n;k++)
			if(i<=l[k] && r[k]<=j)
			if(w[k]>mx)
				mx=w[k],mxind=k;
			f[i][j]=1ll<<62;
			if(mx==-1)
				f[i][j]=0;
			else
				for(int k=l[mxind];k<=r[mxind];k++)
					f[i][j]=min(f[i][j],f[i][k-1]+f[k+1][j]+mx);
		}
}

inline void print()
{
	printf("%lld\n",f[1][cnt]);
}

int main()
{
	int t;
	scanf("%d",&t);
	for(int i=1;i<=t;i++)
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/81782735