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
*/

浙公网安备 33010602011771号