zoukankan      html  css  js  c++  java
  • 一本通 P1486 【黑暗城堡】


    思路 :这道题既然要求使加入生成树中的点到1号节点的距离最小,那么我们可以理解为题目要求一个最短路径生成树,那么我们可以从1号节点向每个节点跑一遍SPFA最短路,并记录下来。这道题中如果满足两个点i,j && dis[i] = dis[j] + f[i][j](dis[i]表示第i个点到1号节点的最短距离,f[i][j]表示i向j连的直接路径的长度)那么就满足题目中的条件(生成树中的某个点到1号节点的路径等于从当前点到1号节点的最短路径),所以当前点的答案数++,最后再用乘法原理把他们的方案数乘起来。

    证明一下为什么 dis[i] = dis[j] + f[i][j] 答案数就++ :

    如样例图所示:

    我们手动模拟求得dis[1] = 0, dis[2] = 1, dis[3] = 2,  dis[4] = 3(f的就不求了)

    开始模拟:

    • 第2号节点 :枚举所有点,显而易见只有dis[2] = dis[1] + f[2][1]的这种情况(每个节点都会有这种情况的,即直接走最短路)
    • 第3号节点 :枚举所有点,显而易见有两种情况,一是直接走最短路(这里就不写了),二是经过2号节点,再到达1号节点dis[3] = dis[2] + f[3][2]
    • 第4号节点 :枚举所有点,显而易见有三种情况,一是直接走最短路(这里就不写了),二是经过2号节点,再到达1号节点dis[4] = dis[2] + f[4][2],三是经过3号节点,再到达1号节点dis[4] = dis[3] + f[4][3]

    综上所述,如果一个节点可以经过另一个节点到达1号节点,而且距离还是相同的,那么答案数就可以++了。这里采用了Floyed的思想

    那个式子翻译成中文就是如果一个节点到1号节点的最短路 = 另一个和它有连边的节点到根节点的最短路 + 它们两个节点之间的直接距离,那么答案数++,而那条边要不然就是在最短路里,要不然就是另一种方案

    code :

     1 #include <bits/stdc++.h>
     2 #define INF 0x3f3f3f3f
     3 using namespace std;
     4 const long long MOD = pow(2, 31) - 1;//别忘了取膜 
     5 int n, m, x, y, num, head[1000001], vis[1000001];
     6 long long ans, z, dis[1000001], f[1001][1001];//这些变量最好开long long 
     7 struct node
     8 {
     9     int next, to;
    10     long long val;
    11 }stu[1000001];
    12 inline void add(int x, int y, int z)//标准链式向前星 
    13 {
    14     stu[++num].next = head[x];
    15     stu[num].to = y;
    16     stu[num].val = z;
    17     head[x] = num;
    18     return;
    19 }
    20 inline void spfa(int s)//SPFA最短路 
    21 {
    22     memset(vis, 0, sizeof(vis));
    23     memset(dis, INF, sizeof(dis));
    24     queue < int > pru;
    25     pru.push(s);
    26     dis[s] = 0;
    27     vis[s] = 1;
    28     while(!pru.empty())
    29     {
    30         int u = pru.front();
    31         pru.pop();
    32         vis[u] = 0;
    33         for(register int i = head[u]; i; i = stu[i].next)
    34         {
    35             int k = stu[i].to;
    36             if(dis[k] > dis[u] + stu[i].val)
    37             {
    38                 dis[k] = dis[u] + stu[i].val;
    39                 if(!vis[k])
    40                 {
    41                     vis[k] = 1;
    42                     pru.push(k);
    43                 }
    44             }
    45         }
    46     }
    47     return;
    48 }
    49 int main()
    50 {
    51     memset(f, INF, sizeof(f));//初始化 
    52     scanf("%d %d", &n, &m);
    53     for(register int i = 1; i <= m; ++i)
    54     {
    55         scanf("%d %d %lld", &x, &y, &z);
    56         add(x, y, z);//无向图 
    57         add(y, x, z);
    58         f[x][y] = f[y][x] = min(f[x][y], z);//取最小(不知道有没有毒瘤数据) 
    59     }
    60     spfa(1);//从1号节点出发 
    61     ans = 1;//初始化为1 
    62     for(register int i = 2; i <= n; ++i)//1号节点不算 
    63     {
    64         int sum = 0;//当前节点的方案数 
    65         for(register int j = 1; j <= n; ++j)//枚举 
    66         {
    67             if(dis[i] == dis[j] + f[i][j])//不解释 
    68             {
    69                 ++sum;
    70             }
    71         }
    72         if(sum)//这里其实不需要特判,因为每个点都一定会有走最短路这种情况 
    73         {
    74             ans = ans * sum % MOD;//乘法原理 + 边乘边膜 
    75         }
    76     }
    77     printf("%lld", ans);
    78     return 0;
    79 }
  • 相关阅读:
    C#操作json
    sql server 2008 身份验证失败 18456
    MD5密码加密
    oracle dg 报错提示 涉及硬盘错误
    Rhel6.5 相关操作
    Centos6.9部署vnc
    Sqluldr2 libclntsh.so报错处理
    时钟服务器同步方法
    windows copy 和xcopy
    Linux 本地repo配置
  • 原文地址:https://www.cnblogs.com/qqq1112/p/11117346.html
Copyright © 2011-2022 走看看