School Team Contest #1 (Winter Computer School 2010/11) C. Moon Craters(*)

題目鏈接
在這裏插入圖片描述
題意:給出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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章