主题:第40次编程比赛结果
neverPE [专家分:1620] 发布于 2006-09-03 22:12:00
第1题 主要是集合查询和合并。合并的效率很重要,如果能想到并查集,那么做起来就不难,代码量也不大。本来第1题想出图论的,又怕控制不好难度,不过并查集跟树挂钩,也勉强算是图论吧。给出一段代码供参考:
int root(int v,int* set)
{
if (set[v] == v) return v;
return set[v]=root(set[v],set);
}
int ReligionsStd(int n,int m,int* record)
{
int i,count=n;
int* set=new int[n+1];
for (i=0;i<=n;i++) //初始化
set[i]=i;
for (i=0;i<m*2;i+=2)
if (root(record[i],set)!=root(record[i+1],set))//如果属于不同集合
{
set[set[record[i]]]=set[record[i+1]];//合并
count--;
}
delete[] set;
return count;
}
第1轮:
fstream fout ("filename");
n=50000;
m = [color=FF0000]t[/color] -1;
fout<<"1 2"<<endl;
for (i=3;i <= [color=FF0000]t[/color];i+=2)
fout<<i<<' '<<i+1<<endl<<i<<' '<<i-1<<endl;
测试数据由上面的代码生成,[color=FF0000]t[/color]=20,200,2000,20000,50000,这是针对性的数据,如果集合合并效率不高,用这组数据是很痛苦的。本来只是是想测试速度,但很多人的程序都出错了。正确结果依次是49981,49801,48001,30001,1。
1 jackin0627: >10s
2 天边蓝:错误
3 iAkiak: 47ms
5 liyanguestc: 错误
6 joekings:0ms
7 liangbch:错误
8 Cyre:错误
10 yelv:错误
11 joekings: 0ms
12 zheni: 7922ms
13 xiaopangzi:错误
14 wlsss: >10s
15 BigCarrot: <15ms
16 rickone: <15ms
17 孤独的猫:>10s
18 boxertony:Runtime Error
19 NingYusui:错误
20 xyhx:错误
21 eastcowboy:0ms
22 babyzn:错误
23 jfs771:错误
24 hwjian:错误
25 火海时代:错误
26 wshong:>10s
第2轮:
joekings和eastcowboy的程序快的出奇,但很遗憾算法不对。用一组简单的数据可以测出错误。
n=3 m=2
record={1 3 2 3}
第3轮:
12 zheni: >10s
3 iAkiak: 100ms
15 BigCarrot: 37ms
16 rickone: 68ms
多组数据测试,以上3位算法没有本质的差别,但BigCarrot实现的最快。iAkiak用模板在速度上可能有些吃亏。
第2题:第2题是简单博弈论题,实现起来很方便,大家做的正确率也很高。
2 boxertony:0ms
3 joekings:0ms
6 liyanguestc:0ms
7 BigCarrot:0ms
8 孤独的猫:0ms
9 wlsss:0ms
14 forjane:0ms
17 xyhx:0ms
5 ITER:错误
10 hainanlion:错误
11 hwjian: 错误(30位,longlong不够)
12 magicalking:错误 long更不够
13 liangbch:超时
综合以上2题的结果,第40次编程比赛的冠军是[color=FF0000]BigCarrot[/color],恭喜他。
如果对测试结果有任何异议,请尽快跟帖,我会认真复查。
回复列表 (共44个回复)
31 楼
NingYusui [专家分:60] 发布于 2006-09-04 21:47:00
我就是头脑简单,不适合当程序员啊!
这是我第二次独立编程,(以前都是抄书),没想到给我这么大的打击!!!!!!!!
32 楼
boxertony [专家分:23030] 发布于 2006-09-04 22:11:00
[quote]我就是头脑简单,不适合当程序员啊!
这是我第二次独立编程,(以前都是抄书),没想到给我这么大的打击!!!!!!!![/quote]
这算什么打击啊。这次题目做错的那么多人,又不只你一个人,呵呵,做错的人当中不少都是高手啊。谁都会犯错误的,只要你坚持下去,慢慢你就能编出好的程序来了。
33 楼
iAkiak [专家分:8460] 发布于 2006-09-04 23:07:00
嘿嘿,bt真可碍:p
34 楼
boxertony [专家分:23030] 发布于 2006-09-05 10:13:00
根据楼主给出的程序,我略作修改,速度似乎提高了一点点。请楼主帮忙看看有没有问题。
int root0(int v, int *set)
{
while(v != set[v])
v = set[v];
return v;
}
int Religions0(int n, int m, int* record)
{
int i, count=n;
int root1, root2;
int *set = new int[n+1];
for (i=0;i<=n;i++) //初始化
set[i] = i;
for (i=0; i<m*2; i+=2)
{
root1 = root0(record[i], set);
root2 = root0(record[i+1], set);
if (root1 != root2) //如果属于不同集合
{
set[root1] = set[root2];//合并,并作为上一个集合的根
count--;
}
}
delete[] set;
return count;
}
35 楼
neverPE [专家分:1620] 发布于 2006-09-05 11:13:00
看了你的程序,主要是修改了路径压缩部分,不再全部指向根,而是指向上一级。
正确性没有问题,对于之前那一组数据,主要测试几何合并效率,树的深度只有2,速度有提升。但不彻底的路径压缩,是以减慢查询速度为代价,对一般性的数据,查询次数远远大于合并次数,这样做得不偿失。
并查集还有一个重要的提高效率的方法,就是合并两棵树时,将深度小的树作为深度大的树的子树,这称为启发式合并。这里的规模太小,m最大只有500k,体现不出优势,所以我没写。
另外,合并的时候set[root1] = set[root2]可以改成set[root1] = root2
36 楼
boxertony [专家分:23030] 发布于 2006-09-05 12:44:00
我明白了,非常感谢。
37 楼
ITER [专家分:680] 发布于 2006-09-07 12:14:00
今天终于在寝室装上了宽带 能上来看了- -
怎么错了哦 PE兄 能给出出错数据么?
2和11测了下也是对的 是不是表达错误?
我不知道怎么返回TRUE嘛 我返回是:return TRUE
但用cout<<Stone(a,b); 打印出来就成1了 - -
38 楼
neverPE [专家分:1620] 发布于 2006-09-07 13:25:00
我人工测的,测函数返回值,怎么会有PE?
你测下2和12。
你程序当中这一段是多余的,导致出错。
if(1==lena||1==lenb)
{
if('1'==*a||'1'==*b)
return true;
}
39 楼
Slica [专家分:0] 发布于 2006-09-07 16:09:00
第二题不是只要有任何一堆无法被3整除就先手必赢了么?
40 楼
wshong [专家分:1880] 发布于 2006-09-08 21:28:00
怎么没有第41次的?什么时候!
我来回复