回 帖 发 新 帖 刷新版面

主题:第40次编程比赛结果

第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个回复)

沙发

楼主能说说我错哪啦
好吗

板凳

[quote]楼主能说说我错哪啦
好吗[/quote]

你先看看别人的解答。知道了正确的算法,就很容易找到自己的错误。

找不到的话,你测一下2,11,正确答案是True

3 楼

15 BigCarrot
一点问题,new了没delete。如果测试量够大的话...速度反而慢

其实我的代码用release还是挺快的:)修改一下
[code]
#include <cstdio>
#include <cassert>
#include <vector>

using namespace std;

struct UFSet
{
    UFSet(int count) : buf(count + 1, 0), island(count), parent(buf.begin())
    {
    }
    int island;
    void Union(int a, int b)
    {
        int la, lb;
        int sa = Find(a, la), sb = Find(b, lb);
        if (sa == sb)
            return;
        if (la > lb)
        {
            parent[sb] = sa;
            if (a != sa)
                parent[a] = sa;
            parent[b] = sa;
        }
        else
        {
            parent[sa] = sb;
            if (b != sb)
                parent[b] = sb;
            parent[a] = sb;
        }
        island--;
    }
    int Find(int a, int &len)
    {
        assert(a > 0 && a < buf.size());
        len = 0;
        while(parent[a] > 0)
            a = parent[a], len++;
        return a;
    }
    vector<int> buf;
    int *parent; // 加个指针
};
int Religions(int n,int m, const int* record)
{
    UFSet s(n);
    int i, a;
    for (i = 0; i < m; i++)
    {
        a = *record++;
        s.Union(a, *record++);
    }
    return s.island;
}
[/code]
debug下开销主要在函数调用上了。每个vector::operator []也要多几次函数调用。
到release都inline了就差不多了。

4 楼

稍微改了下:

int data[50000];
int Religions(int n,int m,int* record){
    int count=0;
    for(int i=0;i<n;i++)
        data[i]=1;
    for( i=0;i<m;i++){
        if(data[ record[2*i] ]==1&&data[ record[2*i+1] ]==1){
            count++;
            data[ record[2*i]-1]=0;
            data[ record[2*i+1-1] ]=0;
        }
        else{
            data[ record[2*i]-1 ]=0;
            data[ record[2*i+1]-1 ]=0;
        }
    }
    for(i=0;i<n;i++)
        count+=data[i];
    return count;
}

楼主有时间指点下...

5 楼

[quote]稍微改了下:

int&nbsp;data[50000];
int&nbsp;Religions(int&nbsp;n,int&nbsp;m,int*&nbsp;record){
&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;count=0;
&nbsp;&nbsp;&nbsp;&nbsp;for(int&nbsp;i=0;i<n;i++)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data[i]=1;
&nbsp;&nbsp;&nbsp;&nbsp;for(&nbsp;i=0;i<m;i++){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(data[&nbsp;record[2*i]&nbsp;]==1&&data[&nbsp;record[2*i+1]&nbsp;]==1){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;count++;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data[&nbsp;record[2*i]-1]=0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data[&nbsp;record[2*i+1-1]&nbsp;]=0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data[&nbsp;record[2*i]-1&nbsp;]=0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data[&nbsp;record[2*i+1]-1&nbsp;]=0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;for(i=0;i<n;i++)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;count+=data[i];
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;count;
}

楼主有时间指点下...[/quote]
答案错了哈!!我的方法类似
第一组测试数据都不能通过!!

6 楼

To 4楼的天边蓝:我已经给出了第1组测试数据及答案,请至少先通过这一组数据再提交。

To 3楼的iAkiak:你的程序本来就很快:)修改之后和Rickone速度相当。你在合并2棵树的时候还考虑了树的深度,本来应该更快,但在这个程序使用vector实在没有必要。 BigCarrot没有delete,不是个好习惯,这个程序里每次最多只new200KB,倒问题不大。

7 楼

仔细看了BigCarrot的算法,跟我想的一样,不知道怎么慢那么多,函数调用开销没这么大吧~~

8 楼

楼主能否把导致内存溢出的测试数据给我?谢谢。我自己测试没有遇到这种情况。

9 楼

回楼上,函数调用不是问题。你看我给的参考代码,不但是频繁的函数调用,而且是递归,但速度并不比BigCarrot慢。
你们3个都是并查集,同样的算法,就看谁的实现更快。我又看了下你的程序,DifferRoot()函数中,有些操作不是必须,还有优化空间。

10 楼

怎么比赛的帖子不可以收藏?

是每周一次比赛吗?

我来回复

您尚未登录,请登录后再回复。点此登录或注册