Everything that kills me makes me feel alive.

P4766 [CERC2014]Outer space invaders 题解

题目链接

小小讲一讲吧,写篇题解。

条件

  • \(n\) 非常小,大概 \(n^3\) 能过。

  • 有编号,时间,距离三个要素。

  • 时间很大,不可能直接作为数组的两维。

思路

出于对上述条件的考虑,一位大佬思考过后决定使用区间dp,并教会了我。

  • 用离散化后的时间作为数组的两维。

  • 而后每次枚举时间的时候,找到这在当前时间区间中距离最大的外星人。由于这个外星人必须被杀,且杀完它之后其他外星人都被杀了,所以我们直接考虑它就可以了。

状态转移方程

\[dp_{i,j}=\min \limits_{k=l_{id}}^{r_{id}}(dp_{i,j},dp_{i,k-1}+dp_{k+1,j}+d_{id}) \]

\(id\) 为当前区间距离最大的外星人的编号。

code

#include<bits/stdc++.h>
using namespace std;
const int N=750,Inf=11000*300;

template<class T> T read(T &x){
	char c=getchar();bool f=0;x=0;
	while(!isdigit(c)) f|=c=='-',c=getchar();
	while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return f?-x:x;
} 

int T,n;
int dp[N][N],tim[N],id[11000];//tim为离散数组,注意数组的大小 
struct node{
	int l,r,d;
}a[N];

int main(){
	read(T);
	while(T--){
		read(n);
		int cnt=0;
		memset(dp,0,sizeof(dp));//初始化重点
		for(int i=1;i<=n;i++) read(a[i].l),read(a[i].r),read(a[i].d),tim[++cnt]=a[i].l,tim[++cnt]=a[i].r;
		sort(tim+1,tim+cnt+1);
		for(int i=1;i<=cnt;i++) id[tim[i]]=i;
		for(int i=1;i<=n;i++) a[i].l=id[a[i].l],a[i].r=id[a[i].r];//离散化
		for(int len=1;len<cnt;len++){
			for(int i=1;i+len<=cnt;i++){
				int j=i+len,now=0;
				dp[i][j]=Inf;//初始化 
				for(int k=1;k<=n;k++){//寻找max
					if(a[k].l>=i&&a[k].r<=j)
					 	if(!now||a[k].d>a[now].d) now=k;
				}
				if(!now) {dp[i][j]=0;continue;}//dp[i][j]=0没有敌人 
				for(int k=a[now].l;k<=a[now].r;k++) dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]+a[now].d);
			}
		}
		printf("%d\n",dp[1][cnt]);
	}
}
/*
1
3
1 4 4
4 7 5
3 4 7
*/
/*
7
*/
posted @ 2022-07-25 17:42  wind_seeker  阅读(52)  评论(0)    收藏  举报
Live2D