codility上的问题(37) Magnesium 2014

这个题也比较简单,给定一个无向图,不保证是平面图,可能有自环,有重边,总之是任意一个无向图。有边权,你可以从任何点出发,任何点结束,可以经过同一个定点任意多次。但是你走过的路必须满足所有边的权值严格单调递增,求最长能经过多少条边。

图是按照边给定的,函数头部:

int solution(int N, vector<int> &A, vector<int> &B, vector<int> &C)

其中 N 表示节点数,A B 表示边的定点[0..N-1],C表示边权。

数据范围:节点数N [1..2*10^5],边数[0..2*10^5],权值范围[1..10^9],整数。

要求时间复杂度:O(N + MlogM),空间复杂度O(N + M)。

分析: 有点dp的思路,如果我们把边按照权重排序,则直接加边就可以了。例如dp[x]表示当前以x为终点的最长路。那么加上一条边(x,y)后,dp[y] = max(dp[x] + 1, dp[y]),大概就是这个思路。但是注意边权有相同的,我们必须把相同边权的边统一一起处理掉,并且暂时不能更新,只有等所有相同边权的边都计算完之后再更新。因为是按边处理的,所以复杂度是O(M),当然还有排序的O(MlogM),感觉没N的事。。。

代码:

// you can also use includes, for example:
// #include <algorithm>

#include <algorithm>

int solution(int N, vector<int> &A, vector<int> &B, vector<int> &C) {
    // write your code in C++98
    vector<pair<int,pair<int,int> > > road;
    vector<int> level, dist;
    dist.resize(N, 0);
    int result = 0;
    for (int i = 0; i < A.size(); ++i) {
        road.push_back(make_pair(C[i], make_pair(A[i], B[i])));
        road.push_back(make_pair(C[i], make_pair(B[i], A[i])));
    }
    sort(road.begin(), road.end());
    for (int i = 0; i < road.size();) {
        int x = i;
        vector<pair<int,int> > temp;
        for (; (i < road.size()) && (road[x].first == road[i].first); ++i) {
            if (dist[road[i].second.second] <= dist[road[i].second.first]) {
                result = max(result, dist[road[i].second.first] + 1);
               // printf("from = %d, to = %d, level = %d, dist = %d\n",road[i].second.first, road[i].second.second, road[i].first, dist[road[i].second.first] + 1);
                temp.push_back(make_pair(road[i].second.second, dist[road[i].second.first] + 1));
            }
            
        }
        for (int j = 0; j < temp.size(); ++j) {
            dist[temp[j].first] = max(dist[temp[j].first], temp[j].second);
        }
      
    }
    return result;
}



你可能感兴趣的:(Algorithm,算法,codility)