5
0 2
0 3
2 1
1 2
4 0
意为有5只乌龟
第一只乌龟说前面有0只乌龟,后面有2只乌龟
第二只乌龟说前面有0只乌龟,后面有3只乌龟
这些乌龟中一定有撒谎的,否则会发生冲突
对每只乌龟,[ai,bi]表示前面有ai只乌龟,后面有bi只乌龟
所以其位置一定为[ai+1,n-bi]这个区间内,对于例子
[1,3]
[1,2]
[3,4]
[2,3]
[5,5]
第一只乌龟和第二只乌龟的区间重叠,则第一只乌龟和第二只是不能同时选择的,而完全重复是允许的,因为允许并列
问题变成求不重叠的区间集合的最大区间数,完全重复的两个可认为是一个权为2的区间
注意[1,3]这个区间的最大就是3
0 2
0 3
2 1
1 2
4 0
意为有5只乌龟
第一只乌龟说前面有0只乌龟,后面有2只乌龟
第二只乌龟说前面有0只乌龟,后面有3只乌龟
这些乌龟中一定有撒谎的,否则会发生冲突
对每只乌龟,[ai,bi]表示前面有ai只乌龟,后面有bi只乌龟
所以其位置一定为[ai+1,n-bi]这个区间内,对于例子
[1,3]
[1,2]
[3,4]
[2,3]
[5,5]
第一只乌龟和第二只乌龟的区间重叠,则第一只乌龟和第二只是不能同时选择的,而完全重复是允许的,因为允许并列
问题变成求不重叠的区间集合的最大区间数,完全重复的两个可认为是一个权为2的区间
注意[1,3]这个区间的最大就是3
然后就是一个区间DP问题了
此题有些trick
比如ai+1>n-bi这种样例也有
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
class Interval
{
public:
int L;
int R;
vector<int>num;//这个区间里的乌龟的编号
}a[1100];//区间
bool operator<(Interval a,Interval b)
{
return a.R<b.R;
}
vector<int>ans;
int Hash[1100][1100];
int d[1100];
//d[i]表示前i个区间能选取的最大权值
//d[i]=d[i-1] 不选取第i个区间
//d[i]=d[p[i-1]+1]+a[i-1] 选取第i个区间
int p[1100];
int n;
bool flag[1100];//flag[i]表示d[i]是否经过d[p[i-1]]计算而来
void Run()//求解DP
{
//首先计算p数组
memset(p,-1,sizeof(p));
for(int i=0;i<n;i++)
{
for(int j=i-1;j>=0;j--)
{
if(a[j].R<a[i].L)
{
p[i]=j;
break;
}
}
}
//p数组计算完成,若没有合法的p,则为-1
d[0]=0;//前0个区间的最大权值是0
for(int i=1;i<=n;i++)//d[i]表示前i个区间的最大值
{
d[i]=d[i-1];
if(p[i-1]==-1)
{
d[i]=max(d[i],(int)a[i-1].num.size());
}
else
{
d[i]=max(d[i],(int)a[i-1].num.size()+d[p[i-1]+1]);
}
if(d[i]!=d[i-1])//不是由d[i-1]计算而来
{
flag[i]=true;
}
}
}
void Insert(int x)
{
for(vector<int>::iterator i=a[x].num.begin();i!=a[x].num.end();i++)
{
ans.push_back(*i);
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(~scanf("%d",&n))
{
int tn=n;//保存一开始的n
memset(flag,false,sizeof(flag));
int m=0;//计算区间个数
ans.clear();//结果数组
memset(Hash,-1,sizeof(Hash));//映射到a数组
for(int i=0;i<n;i++)
{
int ai,bi;
scanf("%d%d",&ai,&bi);
ai++;
bi=n-bi;
if(ai>bi)
{
ans.push_back(i+1);
continue;
}
if(Hash[ai][bi]==-1)//没有出现过这个区间
{
a[m].L=ai;
a[m].R=bi;
a[m].num.clear();
a[m++].num.push_back(i+1);
Hash[ai][bi]=m-1;
}
else//已经出现了
{
if(bi-ai+1==a[Hash[ai][bi]].num.size())//此区间已经饱和
{
ans.push_back(i+1);//一定说谎
}
else
{
a[Hash[ai][bi]].num.push_back(i+1);
}
}
}
n=m;
//现有n个区间,选取不重叠的区间的子集使权最大
sort(a,a+n);
Run();
//dp[n]即为前n个区间获取的最大权值,最大乌龟数
printf("%d",tn-d[n]);
int now=n;
while(now>0)
{
if(flag[now])//d[p[now-1]+1]->d[now]
{
for(int i=p[now-1]+1;i<now-1;i++)
{
Insert(i);//
}
now=p[now-1]+1;
}
else//d[now-1]->d[now]
{
Insert(now-1);
now--;
}
}
sort(ans.begin(),ans.end());
for(vector<int>::iterator i=ans.begin();i!=ans.end();i++)
{
printf(" %d",*i);
}
printf("\n");
}
return 0;
}