题意:n个人,每个人有两个属性S和B,每两个人之间,如果不是一个人两个属性都严格高于另一个人,他们就会互相hate。求最多能有多少人在一起,互相不会hate。
思路:最长公共子序列。我们可以这样考虑,按S升序排序,S相同的人分为一档,每档里面最多只能选一个人,否则就会互相hate。如果B也升序排序,问题就变成了每段只能选一个的最长公共子序列。但是,如果B降序排序呢,这样排序之后再求LIS就自动保证了S各不相同,问题也就转换成了普通的LIS。还有就是需要开辅助的数组记录选择,算法得用O(nlogn)的,否则超时。
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
#define INF 1000000010
struct mem{
int s;
int b;
int index;
};
mem M[100010];
int dp[100010];
int dp2[100010];
int last[100010];
int choose[100010];
bool cmp(mem a,mem b){
if(a.s==b.s)return a.b>b.b;
return a.s<b.s;
}
int main(){
int n;
while(cin>>n){
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++){
scanf("%d%d",&M[i].s,&M[i].b);
M[i].index=i;
dp2[i]=INF;
}
sort(M+1,M+n+1,cmp);
int ans=0;
int k;
for(int i=1;i<=n;i++){
int find=-1;
int l=1;int r=ans+1;//二分查找
while(l!=r){
int mid=(l+r)/2;
if(M[i].b<dp2[mid]){
if(M[i].b>dp2[mid-1]){
find=mid;break;
}else{
r=mid;
}
}else{
if(l!=mid)l=mid;
else l++;
}
}
if(M[i].b>dp2[l-1]&&M[i].b<dp2[l])find=l;
if(find==-1)continue;
if(find>=dp[i]){
dp2[find]=M[i].b;
dp[i]=find;
choose[find]=i;
last[i]=choose[find-1];
if(find>ans){
ans=find;
k=i;
}
}
}
cout<<ans<<endl;
while(k){
printf("%d ",M[k].index);
k=last[k];
}
printf("\n");
}
return 0;
}
本文介绍了一种解决特定人际关系问题的方法,通过将问题转化为最长公共子序列问题,并利用降序排列和最长递增子序列算法来高效求解。文章详细展示了如何通过排序和动态规划算法来找出最大数量的互不敌视的人群组合。
503

被折叠的 条评论
为什么被折叠?



