QQ复赛C题

nandizhu 2009-05-17 07:28:49
Description

Richard对图的顶点聚类问题非常感兴趣,这一次,他提出了一个新的想法。

假如现在有n个顶点(从0开始编号),每个顶点x有两个值,分别表示为f(x)和g(x)(都是整数范围,即int范围)。对于顶点x,其它任一顶点y到x的距离为d = ( f(y)-f(x) )/( g(y)-g(x) )。开始时,图中没有边,现在对每个顶点x执行以下算法来向图中添加边:

从所有异于x的点中选取一个顶点y,使得y到x的距离d是所有点中最小的,并且d ≥ 0。如果有多种选择,则选abs(f(y)-f(x))最小的一个(abs(t)表示取t的绝对值),如果有多个abs(f(y)-f(x))相等,则选择f(y)-f(x)>0的那个点;
添加无向边(x, y)(如果这条边已经存在,则不重复添加).
这样一来,所有顶点一定在某个聚类的簇中。Richard现在想设计一个查询工具,对于给定的任意两点x和y,能够快速知道它们是不是在同一个簇中(即是否存在一条x到y的路径)?

Input

第一行两个数:n(2 ≤ n ≤ 50,000)和K(1 ≤ K ≤ 100,000)
接下来有n行:第i行的两个数分别表示第i个点的f(i)和g(i)。输入保证任意两个点x和y满足f(x) != f(y),g(x) != g(y)。
接下来K个Query,每个Query包含两个数x和y。

Output

对每一个Query,如果x和y在同一个簇中,输出yes,否则输出no。

Sample Input

4 3
0 0
1 1
2 2
3 -1
0 1
1 2
2 3Sample Output

yes
yes
no
...全文
413 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
lvjaio5241 2009-05-24
  • 打赏
  • 举报
回复
学习
青蛙果果 2009-05-23
  • 打赏
  • 举报
回复
回帖是美德
Dancing_Sea 2009-05-23
  • 打赏
  • 举报
回复
LZ方向错了。

按LS的能够得到结果


struct Pnt
{
int m_x;
int m_y;
}

int Compare(Pnt &p1, Pnt &p2)
{
if (p1.m_x > p2.m_x) return 1;
if (p1.m_x < p2.m_x) return -1;
return p1.m_y - p2.m_y;
}
这么排序后,不需要分1/3象限,负数不需要考虑,实在需要考虑,那么将所有的数平移到第一象限即可
绿色夹克衫 2009-05-22
  • 打赏
  • 举报
回复
说起来确实比较麻烦,程序编起来却比较简单。如果考虑x,y同为负数的情况,那么需要从头到尾再从尾到头遍历两遍,
然后再将最大值合并一遍,共3遍,应该就可以建图了!

定义一个指针m,从前向后遍历的时候,所有点只比较x值小于当前点的点,比如先从p2开始,计算p1,p2的斜率k1,同时将p1,p2作为p2的簇,将m指向p1
然后计算p3,p2的斜率k2,以及p3同m指向点的斜率km,k2 >= km,则将m指向p2,将p2,p3最为p3的簇,如果k2 < km,则将p3同m指向的点作为簇,
继续处理p4......,然后在用同样的方法从后向前处理一遍。(实际上就是分别处理1、3象限的斜率,从前往后是第3象限,从后往前是第1象限)

然后再比较向后和向前的斜率,按照规则挑出二者中最大的。
这样处理完了,就会得到每个点对应的簇了,再次查询就只需要O(1)了!

[Quote=引用 15 楼 nandizhu 的回复:]
引用 13 楼 litaoye 的回复:
应该可以做到n*log(n),先用n*log(n)排个序,然后从后向前遍历,应该可以用O(n)求出所有簇,
此后每次查询应当可以达到O(1)。所以整个算法应当是n*log(n)的!

看来有时候画个图比只用脑子傻想管用的多!


求的D是斜率,如何在对X排序后只用o(n)就可以建图呢??费解??
[/Quote]
nandizhu 2009-05-21
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 litaoye 的回复:]
应该可以做到n*log(n),先用n*log(n)排个序,然后从后向前遍历,应该可以用O(n)求出所有簇,
此后每次查询应当可以达到O(1)。所以整个算法应当是n*log(n)的!

看来有时候画个图比只用脑子傻想管用的多!
[/Quote]

求的D是斜率,如何在对X排序后只用o(n)就可以建图呢??费解??
Fashionxu 2009-05-21
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 nandizhu 的回复:]
是WA啊、。。不是超时。。。让我很郁闷
[/Quote]
WA啥意思?错误的算法?
绿色夹克衫 2009-05-19
  • 打赏
  • 举报
回复
没有想得很清楚,不过感觉用N*log(n)的时间做预处理,之后每查询一对节点,应当是O(1)。
LZ给个原题的连接吧,我写程序提交一下试试!
绿色夹克衫 2009-05-19
  • 打赏
  • 举报
回复
不敢说一定有k*log(n)的解法,但对所有的点按照f(x)排个序,然后计算一下相邻点的距离d,
可以把整个序列分为若干个上升序列,d的最大值应当只会出现在这些序列的端点上。
这样优化之后的复杂度具体是多少我也说不好,不过感觉对由这些端点所组成的点集,还可以继续采用这种方法进行优化。
绿色夹克衫 2009-05-19
  • 打赏
  • 举报
回复
应该可以做到n*log(n),先用n*log(n)排个序,然后从后向前遍历,应该可以用O(n)求出所有簇,
此后每次查询应当可以达到O(1)。所以整个算法应当是n*log(n)的!

看来有时候画个图比只用脑子傻想管用的多!
nwao7890 2009-05-19
  • 打赏
  • 举报
回复
好,记下来,下班再研究
nandizhu 2009-05-18
  • 打赏
  • 举报
回复
是WA啊、。。不是超时。。。让我很郁闷
绿色夹克衫 2009-05-18
  • 打赏
  • 举报
回复
感觉可能有k*log(n)的解法,对于这类跟斜率相关的问题,可以参看以前的一个帖子

http://topic.csdn.net/u/20090117/17/ccfd6178-48fb-40ea-aa5b-f99330769ec5.html

具体方法我再想想!
Paradin 2009-05-18
  • 打赏
  • 举报
回复
upup
绿色夹克衫 2009-05-18
  • 打赏
  • 举报
回复
不过是因为超时还是算错了?
从数据量上来看n^2恐怕有些问题!
jiyan1221 2009-05-18
  • 打赏
  • 举报
回复
这个。。。真不懂
liao05050075 2009-05-17
  • 打赏
  • 举报
回复
初赛答对3题能过.
话说这个题目我也没能做出来
jieao111 2009-05-17
  • 打赏
  • 举报
回复
都参加复赛了,厉害阿,初赛答对几题能过?
nandizhu 2009-05-17
  • 打赏
  • 举报
回复
帮帮忙找找代码的错误哈。。。。。。。
nandizhu 2009-05-17
  • 打赏
  • 举报
回复
我的做法是先依次搜索每个点的连线,然后合并两点的连通分量,复杂度为o(n^2)
但是做的时候一直通不过。。。不知道问题出在哪了,贴上来各位看看。。。。。。

#include <iostream>
#include <cmath>

using namespace std;

class datatype //点的类型
{public:
int fx;
int fy;
int parent; //父节点
};
class querytype //查询数据类型
{public:
int x;
int y;
};
class result //当前所选节点类型
{public:
double mol; //分子 f(y)-f(x)
double deno; //分母 g(y)-g(x)
int k; //当前所选节点号
};
int find(datatype *T,int i) //并查集查询父节点
{
while(T[i].parent!=i){i=T[i].parent;}
return i;
}
void f(datatype *T,querytype *Q,int n,int k)
{
result min; //当前最优值
for (int i=0;i<=n-1;++i)
{
min.deno=0; //初始化分母
min.k=i; //初始化连接点编号
for (int j=0;j<=n-1;++j)
{
if (j!=i)
{
double mo1_t=T[j].fx-T[i].fx; //当前分子
double deno_t=T[j].fy-T[i].fy; //当前分母
if (mo1_t/deno_t<0) //D<0返回继续查找
{
continue;
}
if (min.deno==0) //min未设值
{
min.mol=mo1_t;
min.deno=deno_t;
min.k=j;
continue;
}
if (min.mol/min.deno>mo1_t/deno_t) //当前D小于min.D,更新
{
min.mol=mo1_t;
min.deno=deno_t;
min.k=j;
continue;
}
if (min.mol/min.deno==mo1_t/deno_t) //当前d等于min.d
{
if (abs(min.mol)>abs(mo1_t)) //当前分子绝对值小于min.mol
{
min.mol=mo1_t;
min.deno=deno_t;
min.k=j;
}
else if(abs(mo1_t)==abs(min.mol)&&mo1_t>0)//当前分子绝对
{ 值等于min.mol
min.mol=mo1_t; 且mol_t>0
min.deno=deno_t;
min.k=j;
}
continue;
}
}
}
T[i].parent=find(T,min.k); //找到可连接点的父节点,并查集操作
}
for (int i=0;i<=k-1;++i)
{
if(find(T,Q[i].x)!=find(T,Q[i].y))
{
cout<<"no"<<endl;
}
else
cout<<"yes"<<endl;
}
}

int main()
{
int n;
int k;
cin>>n>>k;
datatype *T=new datatype[n];
for (int i=0;i<=n-1;++i)
{
cin>>T[i].fx;
cin>>T[i].fy;
T[i].parent=i;
}
querytype *Q=new querytype[k];
for (int i=0;i<=k-1;++i)
{
cin>>Q[i].x;
cin>>Q[i].y;
}
f(T,Q,n,k);
system("pause");
return 0;
}

33,008

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧