习题:Moon Craters(DP)
题目
思路
比较容易可以将题转换一个意思,
在数轴上有n条线段,最多能选出多少条线段,使其相互之间要么包含,要么不相交
我们考虑到如果直接对于下标来判断两个区间是否有相交的部分是比较难得,
我们考虑直接在数轴上做这件事,
如果是在数轴上做这件事,首先肯定要将点的坐标进行离散化
\(dp[i][j]\)表示区间\(i到j\)的最大的答案
$dp[i][j]=max{dp[i][k]+dp[k][j]} $
之后,因为题目中提到包含关系也要算进了
即如果\(i到j\)本来是一条线段,\(++dp[i][j]\)即可
对于答案的计算,我们记录下每一个区间的分界点即可
这里有一个小优化,我们可以直接固定左端点,枚举右端点
但是这里的DP转移需要加一个\(dp[i+1][j]\)
代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<set>
#include<map>
using namespace std;
struct node
{
int c;
int r;
}a[2005];
struct Node
{
pair<int,int> val;
int id;
friend bool operator < (const Node &a,const Node &b)
{
return a.val<b.val;
}
friend bool operator == (const Node &a,const Node &b)
{
return a.val==b.val;
}
};
int n,cnt;
int dp[4005][4005];//数轴上区间为l~r的最多有多少个圆
int delet[4005][4005];//分界点
bool g[4005][4005];
vector<int> le[4005];
map<int,bool> f;
map<int,int> hashh;
set<Node> s;
int dfs(int l,int r)
{
if(l>r)
return 0;
if(dp[l][r]!=-1)
return dp[l][r];
dp[l][r]=dfs(l+1,r);
delet[l][r]=0;
for(int i=0;i<le[l].size();i++)
if(le[l][i]<=r&&dp[l][r]<dfs(l,le[l][i])+dfs(le[l][i],r))
{
dp[l][r]=dfs(l,le[l][i])+dfs(le[l][i],r);
delet[l][r]=le[l][i];
}
if(g[l][r])
dp[l][r]++;
return dp[l][r];
}
void pr(int l,int r)
{
if(l>r)
return;
if(delet[l][r]==0)
pr(l+1,r);
else
{
pr(l,delet[l][r]);
pr(delet[l][r],r);
}
if(g[l][r])
cout<<(*s.find((Node){make_pair(l,r),0})).id<<' ';
}
int main()
{
ios::sync_with_stdio(false);
memset(dp,-1,sizeof(dp));
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i].c>>a[i].r;
f[a[i].c-a[i].r]=1;
f[a[i].c+a[i].r]=1;
}
for(map<int,bool>::iterator it=f.begin();it!=f.end();it++)
hashh[(*it).first]=++cnt;
for(int i=1;i<=n;i++)
{
le[hashh[a[i].c-a[i].r]].push_back(hashh[a[i].c+a[i].r]);
g[hashh[a[i].c-a[i].r]][hashh[a[i].c+a[i].r]]=1;
s.insert((Node){make_pair(hashh[a[i].c-a[i].r],hashh[a[i].c+a[i].r]),i});
}
cout<<dfs(1,cnt)<<endl;
pr(1,cnt);
return 0;
}

浙公网安备 33010602011771号