C++ 美丽的人-动态规划
我试着解决美女问题,但在一些测试案例中我得到了错误的答案 一个城市中最负盛名的体育俱乐部有N名会员。 它的每一个成员都强壮美丽。更准确地说,i-th 本俱乐部会员(会员按入会时间编号) 俱乐部)有实力和美貌。因为这是一个非常重要的问题 享有盛誉的俱乐部,其成员非常富有,因此 不平凡的人,所以他们常常非常憎恨对方。 严格地说,X先生讨厌俱乐部的第j位成员 伊夫斯先生俱乐部≤ Sj和Bi≥ Bj或if Si≥ Sj和Bi≤ Bj(如果 Mr X的两个性质都大于的相应性质 Y先生,他甚至没有注意到他,另一方面,如果他的两个 财产较少,他非常尊敬Y先生) 为了庆祝新的2003年,俱乐部的管理层 计划组织一次聚会。但是他们担心如果两个 互相憎恨的人会在聚会结束后同时参加聚会 喝一两杯他们就会打架。所以没有两个讨厌的人 应该互相邀请。另一方面,为了保住俱乐部 普雷斯蒂≥ 在适当的层面上,政府希望邀请 尽可能多的人 作为政府中唯一一个不怕碰的人 一台电脑,你要写一个程序,找出该找谁 邀请参加聚会 输入 输入文件的第一行包含整数N—输入文件的编号 俱乐部成员。( 2 ≤ N≤ 100,000 ). 接下来的N行包含两个 每个编号分别为Si和Bi(1≤ 是,比≤ 10^9) 输出 在输出文件的第一行,打印最大数量的 可以被邀请参加聚会的人。在第二行上输出N 整数-以任意顺序邀请的成员数。如果 存在多个解决方案,输出任意一个 基本上,我的方法是:C++ 美丽的人-动态规划,c++,algorithm,dynamic-programming,C++,Algorithm,Dynamic Programming,我试着解决美女问题,但在一些测试案例中我得到了错误的答案 一个城市中最负盛名的体育俱乐部有N名会员。 它的每一个成员都强壮美丽。更准确地说,i-th 本俱乐部会员(会员按入会时间编号) 俱乐部)有实力和美貌。因为这是一个非常重要的问题 享有盛誉的俱乐部,其成员非常富有,因此 不平凡的人,所以他们常常非常憎恨对方。 严格地说,X先生讨厌俱乐部的第j位成员 伊夫斯先生俱乐部≤ Sj和Bi≥ Bj或if Si≥ Sj和Bi≤ Bj(如果 Mr X的两个性质都大于的相应性质 Y先生,他甚至没有注意到他,
D(i)={1+Max(D(j))}
其中j
和D[i]=Max{D[j]+1}
用于j
和Strength[j]
和Beauty[j],如果没有这样的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;
}
#包括
#包括
#包括
使用名称空间std;
类型定义结构{
长整数s;
长int b;
}c_型;
整数比较(常数c_类型和a,
常数c_类型和b){
返回a.s>n;
矢量ct;
ct.resize(n);
//向量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;
向量d(n,1);
向量p(n,-1);
长整型最大值=-1;
长整型最佳结束=-1;
对于(int i=0;i>ct[i].s>>ct[i].b;
}
排序(ct.begin(),ct.end(),compare);
对于(int i=1;i=0;j--)
{
如果((d[j]+1)>d[i])和(ct[j].b cout因此,有一种有趣的方法从几何角度来思考这个问题。想象一下,绘制一个轴上有S,B的图形,并为每个人放置一个x。(也移除任何重复点,即,如果S=S和B=B,您可以移除其中一个)
然后,对于每个点/人,只有矩形中较低和左侧的点才是可行的选择。因此,我可以将代表尊重他们的人数的数字与每个人关联。称这个数字为C
这为a*搜索提供了一个可接受的启发式。从右上角的根节点开始,我的“最佳”move通常是具有最高C数的分支,因为它为以后保留了最多的选项。此外,一旦我找到了树底部的一个根,如果其他分支的C数高于实际人数,我只需要选择其他分支,因此树的大多数分支将很快终止
我怀疑这种类型的搜索平均来说是最优的,但根据点的分布,它可能有缓慢的边缘情况
这说明了它是如何工作的,从某个根节点开始,在第一次运行时,它会到达最高的C数,当它终止时,它会倒计时以提供一个“答案”,因此它只需检查C编号严格大于当前最佳答案的分支。在这种情况下,没有其他分支
直观地很容易看出,如果点在S和B中均匀分布,这可能会非常快,但如果它们在y=x附近强烈聚集,这可能会非常慢,因为这样通常不会很快排除分支。您的解决方案为人员输出不正确的索引。当您对输入进行排序时,他们的排序会改变只需将额外的索引存储到您的结构中并使用它。
但是,您的代码将得到TLE,这是O(N^2)的原因。您需要O(NlogN)解决方案,这是LIS的经典解决方案。这是LIS(最长递增子序列),您的解决方案似乎还可以。假设您有实现错误?(您可以在此处发布解决方案)@juver我已更新我的解决方案。您的解决方案为人员输出了不正确的索引。当您对输入进行排序后,他们的顺序发生了变化。只需将其他索引存储到您的结构中并使用它。但是,您将编写TLE,原因是O(N^2)。您需要O(NlogN)解决方案,这是LIS的经典解决方案。@尤文图斯您应该将此作为答案发布。对于OP,除了尤文图斯所说的,如果可以邀请的最大可能成员数为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;
}