【问题标题】:D-lang being faster than C++? [closed]D-lang 比 C++ 快? [关闭]
【发布时间】:2017-08-23 20:40:48
【问题描述】:

所以我正在为即将举行的算法编程竞赛练习,我偶然发现了前一年的一个问题。

我几乎解决了它(在 C++ 中),但是我遇到了一些超时,所以我看了一下官方的解决方案,它是用 Dlang 编写的。

然后我试图模仿官方答案在 D 中所做的,但我仍然遇到超时(单个输入 > 4 秒)。 Afaik,C++ 应该比 D 快,但是 D 在瞬间解决相同的输入,而 C++ 需要 5 秒以上

这里是D答案代码

import std.stdio;
import std.algorithm;

struct edge {
    int src, des, w, o;

    int opCmp (ref const edge e) const {
        if(w != e.w) return w - e.w;
        else return o - e.o;
    }
};

const int MAXN = 100004, MAXM = 200004;
int N, M, D, ee, weight, days;
int[MAXN] ds;
edge[] edges;

void init() {
    for(int i=1;i<=N;i++) ds[i] = i;
}

int find(int x) {
    return ds[x] = (x == ds[x] ? x: find(ds[x]));
}

bool connected(int x, int y) {
    return find(x) == find(y);
}

bool merge(int x, int y) {
    int xr = find(x), yr = find(y);
    if(xr ^ yr) {
        ds[xr] = yr;
        return 1;
    }
    return 0;
}

void main() {
    scanf("%d%d%d", &N, &M, &D);
    for(int i=1, a, b, c;i<=M;i++) {
        scanf("%d%d%d", &a, &b, &c);
        if(i < N)
            edges ~= edge(a, b, c, 0);
        else
            edges ~= edge(a, b, c, 1);
    }
    edges.sort();
    init();
    int i, maxe=0;
    for(i=0;i<edges.length;i++) {
        auto e = edges[i];
        if(merge(e.src, e.des)) {
            if(e.o)
                days ++;
        }
    }
    printf("%d", days);
}

然后这是我用 C++ 写的作为答案代码的内容

#include <iostream>
#include <vector>
#include <map>
#include <algorithm>

using namespace std;

struct Edge{
    long long source, end, weight, old;
    Edge(long long _s, long long _e, long long _w, long long _o):source(_s), end(_e), weight(_w), old(_o){}
};

int parents[100004];
vector<Edge>edges;

bool inc(Edge a, Edge b)
{
    if(a.weight == b.weight)return a.old > b.old;
    return a.weight < b.weight;
}

long long find(long long node)
{
    if(parents[node] == node)return node;
    else return find(parents[node]);
}

void init(long long M)
{
    for(long long i = 0; i < M; ++i)parents[i] = i;
}

bool connect(long long x, long long y)
{
    long long fx = find(x);
    long long fy = find(y);
    if(fx == fy)return false;
    parents[fx] = fy;
    return true;
}

long long noOfDays()
{
    long long days = 0;
    for(auto edge : edges){
        if(connect(edge.source, edge.end)){
            if(!edge.old)++days;
        }
    }
    return days;
}

int main()
{
    ios::sync_with_stdio(false); 
    long long N, M , D;
    cin >> N >> M >> D;
    N--;
    for(long long i = 0; i < M; ++i){
        long long a,b,c;
        cin >> a >> b >> c;
        if(i < N){
            edges.push_back(Edge(a,b,c,1));
        }else{
            edges.push_back(Edge(a,b,c,0));         
        }
    }
    sort(edges.begin(), edges.end(), inc);
    init(N+2);
    cout << noOfDays() << endl;
}

在 C++ 上需要超过 5 秒的输入,在 D 上需要一瞬间的输入可以在这里找到“http://ddl3.data.hu/get/356808/10699419/s4.24.in

这是我实际上试图解决的问题“https://dmoj.ca/problem/ccc17s4”(我只做 11 点部分)。

有什么方法可以让我的 C++ 代码和 D 代码一样快?为什么我的 C++ 代码的运行速度不如 D 代码快?


编辑:对于所有澄清,g++ 用于 C++,没有任何优化,“dmd”用于 Dlang,也没有任何优化

【问题讨论】:

  • 您是否在编译时进行了优化?
  • 网站可能对 C++ 和 D 有不同的时间限制。
  • 看起来您需要执行一些分析以查看 C++ 代码中的瓶颈所在。
  • @Mandy - 对于 c++:edges.reserve(M)for(... 之前?还有edges.emplace_back() 而不是edges.push_back()
  • 为什么你的sn-ps如此不同?不同的逻辑流程?不同的名字?很难比较为什么一个会比另一个更快......

标签: c++ algorithm c++11 d


【解决方案1】:

find() 似乎被大量使用,它们在 D 和 C++ 实现中非常不同:

int find(int x) {
    return ds[x] = (x == ds[x] ? x: find(ds[x]));
}

对比:

long long find(long long node)
{
    if(parents[node] == node)return node;
    else return find(parents[node]);
}

find() 在 D 中修改数组(看起来像是某种动态编程,您是否兑现了先前的结果),而在 C++ 中您总是进行完整查找。您应该将苹果与苹果进行比较,尤其是这段代码可以用 C++ 完全相同的方式编写。

【讨论】:

  • (使以前的结果可供重用应该最有可能读取缓存。)
【解决方案2】:

出于好奇,我尝试运行 OPs 代码以及下面的版本,我通过对“D”代码进行最低限度的调整来创建它,以便它可以在 C++ 下编译。 OPs C++ 版本运行大约需要 12 秒。下面的版本运行大约需要 0.25 秒。

我的结论是,对于这个问题的回答是,OP 看到的运行时间差异可能是由于其他一些答案中描述的实现差异,而不是 C++ 的性能不佳。

#include <cstdio>
#include <vector>
#include <algorithm>

struct edge {
    edge(int src, int des, int w, int o) : src(src), des(des), w(w), o(o) {}

    int src, des, w, o;

    int opCmp(const edge& e) const {
        if (w != e.w) return w - e.w;
        else return o - e.o;
    }
};

const int MAXN = 100004, MAXM = 200004;
int N, M, D, ee, weight, days;
int ds[MAXN];
std::vector<edge> edges;

void init() {
    for (int i = 1; i <= N; i++) ds[i] = i;
}

int find(int x) {
    return ds[x] = (x == ds[x] ? x : find(ds[x]));
}

bool connected(int x, int y) {
    return find(x) == find(y);
}

bool merge(int x, int y) {
    int xr = find(x), yr = find(y);
    if (xr ^ yr) {
        ds[xr] = yr;
        return 1;
    }
    return 0;
}

void main() {
    std::scanf("%d%d%d", &N, &M, &D);
    for (int i = 1, a, b, c; i <= M; i++) {
        scanf("%d%d%d", &a, &b, &c);
        if (i < N)
            edges.push_back(edge(a, b, c, 0));
        else
            edges.push_back(edge(a, b, c, 1));
    }
    std::sort(edges.begin(), edges.end(), [](const edge& lhs, const edge& rhs) { return lhs.opCmp(rhs) < 0; });
    init();
    int i, maxe = 0;
    for (i = 0; i<edges.size(); i++) {
        auto e = edges[i];
        if (merge(e.src, e.des)) {
            if (e.o)
                days++;
        }
    }
    printf("%d", days);
}

【讨论】:

    【解决方案3】:

    导致 C++ 版本性能下降的一个可能因素是“inc”函数。它按值接收 2 个“边缘”结构,在 C++ 中,这意味着在 main() 结束时的排序调用期间为每次比较复制结构。

    尝试将“inc”的签名更改为接受“const Edge&”而不是“Edge”。这将导致结构值通过引用传递,从而避免额外的复制。

    此外,如果您运行分析器,您应该能够找到大部分时间都花在了哪里。这是进行优化的“正确”方法:测量以找出性能瓶颈所在,解决瓶颈并再次测量以确认您确实提高了性能。

    【讨论】:

    • 我怀疑这会有很大的不同
    猜你喜欢
    • 2015-06-22
    • 1970-01-01
    • 2011-07-05
    • 2011-10-20
    • 2019-04-30
    • 2016-07-04
    • 2010-10-11
    • 2023-03-17
    • 2013-05-15
    相关资源
    最近更新 更多