題目鏈接
題意:給出n個圓心在x軸上的圓的圓心橫座標和半徑,要求從其中選出儘可能多的圓使得任意兩圓只能是相鄰、相切或包含,問最多可以選出多少圓滿足條件
思路:題意轉化一下,問題轉化爲給出nn個區間,選取儘可能多的區間使得所選任意兩個區間不能相交,把區間端點離散化變成mm個端點,記錄每個端點作爲左端點時對應的右端點集合,以dp[i][j]dp[i][j]表示ii端點到jj端點可以選的圓的最大數量,對於ii端點可選可不選,不選ii端點則狀態變爲dp[i+1][j]dp[i+1][j],選ii端點則要枚舉其對應的右端點kk,進而狀態變成dp[i][k]+dp[k][j]dp[i][k]+dp[k][j],從這些狀態中選取最優值賦給dp[i][j]dp[i][j]即可,注意如果i,ji,j兩端點形成的區間存在,則答案加一,記憶化搜索求出所有dpdp值,答案即爲dp[1][m]
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=4005;
int dp[maxn][maxn],vis[maxn][maxn],u[maxn],v[maxn],num[maxn],c[maxn][maxn];
vector<int>g[maxn];
int dfs(int l,int r)
{
if(l>=r) return dp[l][r]=0;
if(dp[l][r]!=-1) return dp[l][r];
dp[l][r]=dfs(l+1,r);//不選
for(int i:g[l])
{
int t=v[i];
if(t<r)
{
if(dp[l][r]<dfs(l,t)+dfs(t,r))
dp[l][r]=dp[l][t]+dp[t][r],c[l][r]=i;
}
}
return dp[l][r]+=(vis[l][r]>0);
}
void check(int l,int r)
{
if(l>=r) return ;
if(vis[l][r]) printf("%d ",vis[l][r]);
if(c[l][r])
{
check(l,v[c[l][r]]);
check(v[c[l][r]],r);
}
else check(l+1,r);
}
int main()
{
int n,x,t,m=0;
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%d %d",&x,&t);
ll l=x-t,r=x+t;
num[++m]=l,num[++m]=r;
u[i]=l,v[i]=r;
}
sort(num+1,num+1+m);
int size=unique(num+1,num+1+m)-num-1;
for(int i=1;i<=n;++i)
{
u[i]=lower_bound(num+1,num+1+size,u[i])-num;
v[i]=lower_bound(num+1,num+1+size,v[i])-num;
g[u[i]].push_back(i);
vis[u[i]][v[i]]=i;
}
memset(dp,-1,sizeof(dp));
printf("%d\n",dfs(1,size));
check(1,size);
}