POJ2168 Joke with Turtles

来源:互联网 发布:苹果7铃声下载软件 编辑:程序博客网 时间:2024/05/01 13:07
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

然后就是一个区间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,则为-1d[0]=0;//前0个区间的最大权值是0for(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;//保存一开始的nmemset(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;}


原创粉丝点击