美丽的人-动态规划

3

我正在试图解决http://acm.sgu.ru/problem.php?contest=0&problem=199上的美丽人问题,但在一些测试用例中得到了错误的答案。

一座城市中最负盛名的运动俱乐部有N个成员。每个成员都强壮而美丽。更准确地说,该俱乐部的第i位成员(成员按他们加入俱乐部的时间编号)具有力量Si和美丽Bi。由于这是一个非常负有声望的俱乐部,其成员非常富有,因此是非凡的人,他们经常极度憎恨彼此。严格来说,如果Si ≤ Sj并且Bi ≥ Bj或者Si ≥ Sj并且Bi ≤ Bj(如果Mr X的两个属性都大于Mr Y的相应属性,则他甚至不会注意到他,另一方面,如果他的两个属性都较小,则他非常尊重Mr Y),则俱乐部的第i位成员Mr X憎恨俱乐部的第j位成员Mr Y。
为了庆祝新的2003年,俱乐部的管理层计划组织一次聚会。但是,他们担心如果两个互相憎恨的人同时参加聚会,在喝上一两杯之后,他们会开始打架。因此,不应邀请任何互相憎恨的两个人。另一方面,为了保持俱乐部的声望,管理层希望邀请尽可能多的人。
作为唯一一个不害怕接触计算机的管理人员,您需要编写一个程序,找出应该邀请哪些人参加聚会。
输入 输入文件的第一行包含整数N-俱乐部成员的数量。(2 ≤ N ≤ 100,000)。接下来的N行分别包含两个数字-Si和Bi(1 ≤ Si,Bi ≤ 10 ^ 9)。
输出 在输出文件的第一行上打印可以邀请参加聚会的最大人数。在第二行中输出N个整数-要邀请的成员编号,顺序任意。如果有几种解决方案,则输出任何一个。
Sample test(s)

Input


4
1 1
1 2
2 1
2 2

Output


2
1 4 

基本上我的方法是:

  1. 首先根据Beauty[]对Strength[]数组进行排序
  2. 创建一个数组D[i],用于存储到i为止的最大lis
  3. 最优解 = D(i) = { 1 + Max ( D(j) ) },其中 j < iD[i] = max{ D[j] +1 } 对于所有的 j < i,满足 Strength[j] < Strength[i]Beauty[j] < Beauty[i],如果不存在这样的j,则 D(i) = 1

我的方法有什么缺陷吗?

我的解决方案:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std; 
typedef struct {
    long int s;
    long int b;
} c_type;
int compare(const c_type &a, 
        const c_type &b) {
    return a.s < b.s;
}

int main( )
{


int n = 0;
cin>>n;
vector<c_type> ct;
ct.resize(n);
//vector<long int> b(n,-1);
//s[0] = 1;
//s[1] = 1;
//s[2] = 2;
//s[3] = 2;
//b[0] = 1;
//b[1] = 2;
//b[2] = 1;
//b[3] = 2;

vector<long int> d(n,1);
vector<long int> p(n,-1);
long int max = -1;
long int bestEnd = -1;
for(int i = 0 ;i<n;i++)
{
    cin>>ct[i].s>>ct[i].b;
}
 sort (ct.begin(), ct.end(), compare);
for(int i  = 1 ; i < n ;i++)
{
    for(int j  = i-1 ; j>=0 ; j--)
    {
        if(((d[j] + 1) > d[i]) and (ct[j].b < ct[i].b) and (ct[j].s < ct[i].s))
        {
            d[i] = d[j]+1;
            p[i] = j;
        }
    }
    if(max < d[i])
    {
        max = d[i];
        bestEnd = i;
    }
}
cout<<max<<endl;
if(bestEnd != -1)
while(bestEnd not_eq -1)
{
    cout<<bestEnd+1<<" ";
    bestEnd = p[bestEnd];
}
return 0;
}

2
这是LIS(最长递增子序列),你的解决方案看起来没问题。假设你有实现错误?(你可以在这里发布你的解决方案)。 - juver
@juver,我已经更新了我的解决方案。 - EmptyData
1
你的解决方案输出了错误的人员索引。当你对输入进行排序时,他们的顺序发生了变化。只需将额外的索引存储到你的结构中并使用它即可。但是,由于O(N ^ 2)的时间复杂度,你的代码会超时。你需要O(NlogN)的解决方案,这是LIS的经典解法。 - juver
@juver 你应该将这个作为答案发布。对于OP来说,除了juver所说的之外,如果最多可以邀请的成员数量为1,则你也没有正确输出。 - Abhishek Bansal
这个俱乐部的每个人都讨厌自己;-)(因此,可以邀请的最大人数是0,以免发生争斗。摇滚 - j_random_hacker
2个回答

2
所以有一种有趣的几何思考方式来解决这个问题。想象一下在S、B轴上绘制一个图表,并为每个人放置一个x。 (还要删除任何重复点,即如果s = s且b = b,则可以只删除其中一个)。
然后对于每个点/人,只有左下角矩形内的点是可行选择。因此,我可以将每个人与代表尊重他们的人数相关联。将此数字称为C。
这为a*搜索提供了一个可接受的启发式方法。从右上角开始,我的“最佳”移动通常是具有最高C数量的移动,因为这样保留了更多的选项以便以后使用。此外,一旦我找到一个根节点到树底部,我只需要选择其他分支,如果它们的C数字高于实际人数,那么大多数树将很快终止。
我怀疑平均而言,这种类型的搜索是最优的,但它可能具有缓慢的边缘情况,具体取决于点的分布。
这演示了它如何工作,您从某个根节点开始,在第一次运行时,它会转到最高的C号码,当它终止时,它会向上计数以提供“答案”,因此它只需检查C号码严格大于当前最佳答案的分支。在这种情况下,没有其他分支。
直观地看,如果S和B中的点均匀分布,则这可能非常快,但如果它们强烈聚集在y = x周围,则可能会非常慢,因为通常不会很快排除分支。

它有完整的O(NlogN)解决方案,正如在作者的问题下评论中所提到的。 - juver
搜索树的平均速度可以比普通搜索快得多。尽管在极端情况下可能会更糟糕。 - phil_20686
虽然构建C数字可能需要NlogN的时间,但这似乎是一种有趣的方法。 - phil_20686

2
你的解决方案输出的人员索引不正确。当你对输入进行排序时,它们的顺序发生了变化。只需将附加索引存储到你的结构中并使用它即可。
但是,由于O(N ^ 2),你的代码会超时。你需要O(NlogN)的解决方案,这是LIS的经典解法。

TLE 和 LIS 是什么意思? - G. Bach
1
LIS - 最长上升子序列,TLE - 在在线评测的背景下,即时间限制超出 - juver

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接