zoukankan      html  css  js  c++  java
  • uva1416 dijkstra

    大白书P330 这题比较麻烦

    给出一个n个节点m条边的无向图,每条边上有一个正权。令c等于每对节点的最短路长度之和。例n=3时, c = d(1,1)+d(1,2)+d(1,3)+d(2,1)+d(2,2)+d(2,3)+d(3,1)+d(3,2)+d(3,3);

    要求删除一条边后使得新的c值c‘最大。不连通的两点的最短路径长度为L

    // LA4080/UVa1416 Warfare And Logistics
    // Rujia Liu
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    #include<queue>
    using namespace std;
    
    const int INF = 1000000000;
    const int maxn = 100 + 10;
    
    struct Edge {
      int from, to, dist;
    };
    
    struct HeapNode {
      int d, u;
      bool operator < (const HeapNode& rhs) const {
        return d > rhs.d;
      }
    };
    
    struct Dijkstra {
      int n, m;
      vector<Edge> edges;
      vector<int> G[maxn];
      bool done[maxn];    // 是否已永久标号
      int d[maxn];        // s到各个点的距离
      int p[maxn];        // 最短路中的上一条弧
    
      void init(int n) {
        this->n = n;
        for(int i = 0; i < n; i++) G[i].clear();
        edges.clear();
      }
    
      void AddEdge(int from, int to, int dist) {
        edges.push_back((Edge){from, to, dist});
        m = edges.size();
        G[from].push_back(m-1);
      }
    
      void dijkstra(int s) {
        priority_queue<HeapNode> Q;
        for(int i = 0; i < n; i++) d[i] = INF;
        d[s] = 0;
        memset(done, 0, sizeof(done));
        Q.push((HeapNode){0, s});
        while(!Q.empty()) {
          HeapNode x = Q.top(); Q.pop();
          int u = x.u;
          if(done[u]) continue;
          done[u] = true;
          for(int i = 0; i < G[u].size(); i++) {
            Edge& e = edges[G[u][i]];
            if(e.dist > 0 && d[e.to] > d[u] + e.dist) { // 此处和模板不同,忽略了dist=-1的边。此为删除标记。根据题意和dijkstra算法的前提,正常的边dist>0
              d[e.to] = d[u] + e.dist;
              p[e.to] = G[u][i];
              Q.push((HeapNode){d[e.to], e.to});
            }
          }
        }
      }
    };
    
    //////// 题目相关
    Dijkstra solver;
    int n, m, L;
    vector<int> gr[maxn][maxn]; // 两点之间的原始边权
    int used[maxn][maxn][maxn]; // used[src][a][b]表示源点为src的最短路树是否包含边a->b
    int idx[maxn][maxn]; // idx[u][v]为边u->v在Dijkstra求解器中的编号
    int sum_single[maxn]; // sum_single[src]表示源点为src的最短路树的所有d之和
    
    int compute_c() {
      int ans = 0;
      memset(used, 0, sizeof(used));
      for(int src = 0; src < n; src++) {
        solver.dijkstra(src);
        sum_single[src] = 0;
        for(int i = 0; i < n; i++) {
          if(i != src) {
            int fa = solver.edges[solver.p[i]].from;
            used[src][fa][i] = used[src][i][fa] = 1;
          }
          sum_single[src] += (solver.d[i] == INF ? L : solver.d[i]);
        }
        ans += sum_single[src];
      }
      return ans;
    }
    
    int compute_newc(int a, int b) {
      int ans = 0;
      for(int src = 0; src < n; src++)
        if(!used[src][a][b]) ans += sum_single[src];
        else {
          solver.dijkstra(src);
          for(int i = 0; i < n; i++)
            ans += (solver.d[i] == INF ? L : solver.d[i]);
        }
      return ans;
    }
    
    int main() {
      while(scanf("%d%d%d", &n, &m, &L) == 3) {
        solver.init(n);
        for(int i = 0; i < n; i++)
          for(int j = 0; j < n; j++) gr[i][j].clear();
    
        for(int i = 0; i < m; i++) {
          int a, b, s;
          scanf("%d%d%d", &a, &b, &s); a--; b--;
          gr[a][b].push_back(s);
          gr[b][a].push_back(s);
        }
    
        // 构造网络
        for(int i = 0; i < n; i++)
          for(int j = i+1; j < n; j++) if(!gr[i][j].empty()) {
            sort(gr[i][j].begin(), gr[i][j].end());
            solver.AddEdge(i, j, gr[i][j][0]);
            idx[i][j] = solver.m - 1;
            solver.AddEdge(j, i, gr[i][j][0]);
            idx[j][i] = solver.m - 1;
          }
    
        int c = compute_c();
        int c2 = -1;
        for(int i = 0; i < n; i++)
          for(int j = i+1; j < n; j++) if(!gr[i][j].empty()) {
            int& e1 = solver.edges[idx[i][j]].dist;
            int& e2 = solver.edges[idx[j][i]].dist;
            if(gr[i][j].size() == 1) e1 = e2 = -1;
            else e1 = e2 = gr[i][j][1]; // 大二短边
            c2 = max(c2, compute_newc(i, j));
            e1 = e2 = gr[i][j][0]; // 恢复
          }
    
        printf("%d %d
    ", c, c2);
      }
      return 0;
    }
    View Code
  • 相关阅读:
    进程管理
    磁盘管理
    用户组管理
    Idea 导入(import)项目和打开(open)项目的区别
    SqlServer--转换varchr值‘2993296307’时溢出了整数列 和 修改 字段类型
    C#--Winform--图标控件Chart详解
    SqlServer--存储过程--自定义存储过程
    SqlServer--存储过程--系统和扩展存储过程(不常用)
    SqlServer--视图
    C#--SqlServer--sql语句拼接和带参数的SQL语句
  • 原文地址:https://www.cnblogs.com/Opaser/p/4320533.html
Copyright © 2011-2022 走看看