zoukankan      html  css  js  c++  java
  • 2069: [POI2004]ZAW

    2069: [POI2004]ZAW

    链接

    题意:

      给定一张带权图(边是双向的,但不同方向长度不同)。求从1出发,至少经过除1外的一个点,再回到1的最短路。点和边不能重复经过。 n≤5000,m≤10000

    分析:

      因为不能重复经过,不能直接最短路的,考虑去掉不能重复经过一个点的限制。

      可以枚举所有与1有边的点,然后从这里面枚举一个点的,求出到其他与1相连的点最短路,来更新。 

      这样显然复杂度是关于1的出度的,复杂度并不是很理想。

      然后这里有一个技巧,按照二进制某一位上的01分成两个集合,然后跑多源最短路。

      为什么可以呢?任何两个不同的点的二进制位最少存在一位不同。  

      复杂度$O(nlog^2n)$

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<cctype>
    #include<set>
    #include<queue>
    #include<vector>
    #include<map>
    #define pa pair<int,int>
    using namespace std;
    typedef long long LL;
    
    inline int read() {
        int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
        for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    }
    
    const int N = 20005, INF = 1e9;
    struct Edge{ int to, nxt, w; } e[50005];
    int head[N], dis[N], df[N], dt[N], A[N], En;
    bool vis[N];
    priority_queue< pa, vector< pa >, greater< pa > > q; 
    
    inline void add_edge(int u,int v,int w) {
        ++En; e[En].to = v, e[En].nxt = head[u], e[En].w = w; head[u] = En;
    }
    void Dijkstra() {
        while (!q.empty()) {
            int u = q.top().second; q.pop();
            if (vis[u]) continue;
            vis[u] = 1;
            for (int i = head[u]; i; i = e[i].nxt) {
                int v = e[i].to;
                if (dis[v] > dis[u] + e[i].w) {
                    dis[v] = dis[u] + e[i].w;
                    q.push(pa(dis[v], v));
                }
            }
        }
    }
    int main() {
        int n = read(), m = read(), cnt = 0;
        for (int i = 1; i <= m; ++i) {
            int u = read(), v = read(), w;
            if (u == 1) {
                df[v] = read(), dt[v] = read();
                if (!vis[v]) vis[v] = 1, A[++cnt] = v;
            }
            else if (v == 1) {
                dt[u] = read(), df[u] = read();
                if (!vis[u]) vis[u] = 1, A[++cnt] = u;
            }
            else {
                w = read();add_edge(u, v, w);
                w = read();add_edge(v, u, w);
            }
        }
        int ans = INF;
        for (int k = 1; k <= cnt; k <<= 1) {
            for (int i = 1; i <= n; ++i) dis[i] = INF, vis[i] = 0;
            for (int i = 1; i <= cnt; ++i) 
                if (i & k) q.push(pa(dis[A[i]] = df[A[i]], A[i]));
            Dijkstra();
            for (int i = 1; i <= cnt; ++i) 
                if (!(i & k)) ans = min(ans, dis[A[i]] + dt[A[i]]);
            
            for (int i = 1; i <= n; ++i) dis[i] = INF, vis[i] = 0;
            for (int i = 1; i <= cnt; ++i) 
                if (!(i & k)) q.push(pa(dis[A[i]] = df[A[i]], A[i]));
            Dijkstra();
            for (int i = 1; i <= cnt; ++i) 
                if (i & k) ans = min(ans, dis[A[i]] + dt[A[i]]);            
        }
        cout << ans;
        return 0;
    }
  • 相关阅读:
    wp8开发时模拟器无法联网解决方法
    软件测试技术---白盒测试
    软件测试技术---代码检查,走查与评审
    简谈WP,IOS,Android智能手机OS
    软件测试技术---在软件生命周期中测试的实施
    软件测试技术---测试的基本概念
    zookeeper源码分析三LEADER与FOLLOWER同步数据流程
    zookeeper源码分析(一) 工作原理
    分布式服务框架 Zookeeper -- 管理分布式环境中的数据
    构建高并发高可用的电商平台架构实践(转)
  • 原文地址:https://www.cnblogs.com/mjtcn/p/10334281.html
Copyright © 2011-2022 走看看