zoukankan      html  css  js  c++  java
  • 洛谷P1144 最短路计数 及其引申思考

    图论题目练得比较少,发一道spfa的板子题目~

    题目:P1144

    题目描述

    给出一个N个顶点M条边的无向无权图,顶点编号为1~N。问从顶点1开始,到其他每个点的最短路有几条。

    输入输出格式

    输入格式:

    输入第一行包含2个正整数N,M,为图的顶点数与边数。

    接下来M行,每行两个正整数x, y,表示有一条顶点x连向顶点y的边,请注意可能有自环与重边。

    输出格式:

    输出包括N行,每行一个非负整数,第i行输出从顶点1到顶点i有多少条不同的最短路,由于答案有可能会很大,你只需要输出mod 100003后的结果即可。如果无法到达顶点i则输出0。

    输入输出样例

    输入样例#1: 
    5 7
    1 2
    1 3
    2 4
    3 4
    2 3
    4 5
    4 5
    
    输出样例#1:
    1
    1
    1
    2
    4
    

    说明

    1到5的最短路有4条,分别为2条1-2-4-5和2条1-3-4-5(由于4-5的边有2条)。

    对于20%的数据,N ≤ 100;

    对于60%的数据,N ≤ 1000;

    对于100%的数据,N<=1000000,M<=2000000。

    Solution:

    一眼数据范围,吓得就是一滚~,关键是还有重边,而且spfa只能记录单点到其它点的一条最短路,这题又要输出最短路个数取模,让人琢磨不透。So,默默的看看标签吧,普及+提高,嗯貌似不是很难,看下解题标签:spfa,bfs,图论,最短路。OK,果然还是要用到spfa,我们关键是要想到如何去处理重边和最短路计数。于是乎,我们先写一下spfa的模板,然后再来思考,不难发现:边权都为1,对于重边在spfa中会进行多次才到下一个点,所以路径数会记录下来,而且在spfa的松弛操作中由于边权均为1所以每个点只会松弛一次,于是乎在跑spfa时我们只需判断dis[v]==dis[u]+1是否成立,若成立,对于ans就加上到u点的边的条数再取模。这样这道题就完美的解决了。

    代码:

     1 #include<bits/stdc++.h>
     2 #pragma GCC optimize(2)
     3 using namespace std;
     4 #define ll long long
     5 #define il inline
     6 #define mod 100003
     7 #define N 1000005
     8 #define inf 233333333
     9 int n,m,h[N],dis[N],cnt,ans[N];
    10 bool vis[N];
    11 queue<int>q;
    12 il int gi()
    13 {
    14     int a=0;char x=getchar();bool f=0;
    15     while((x<'0'||x>'9')&&x!='-')x=getchar();
    16     if(x=='-')x=getchar(),f=1;
    17     while(x>='0'&&x<='9')a=a*10+x-48,x=getchar();
    18     return f?-a:a;
    19 }
    20 struct edge{
    21 int to,net;
    22 }e[N<<2];
    23 il void add(int u,int v){e[++cnt].to=v;e[cnt].net=h[u];h[u]=cnt;}
    24 il void spfa(int s)
    25 {
    26     for(int i=1;i<=n;i++)dis[i]=inf;
    27     q.push(s);
    28     vis[s]=1;ans[s]=1;dis[s]=0;
    29     int u,v;
    30     while(!q.empty())
    31     {
    32         u=q.front();
    33         q.pop();vis[u]=0;
    34         for(int i=h[u];i;i=e[i].net){
    35             v=e[i].to;
    36             if(dis[u]+1<dis[v]){
    37                 dis[v]=dis[u]+1;
    38                 ans[v]=ans[u];
    39                 if(!vis[v])vis[v]=1,q.push(v);
    40             }
    41             else if(dis[v]==dis[u]+1)ans[v]=(ans[v]+ans[u])%mod;
    42         }
    43     }
    44 }
    45 int main()
    46 {
    47     n=gi(),m=gi();
    48     int u,v;
    49     for(int i=1;i<=m;i++)
    50     {
    51         u=gi(),v=gi();
    52         add(u,v);add(v,u);
    53     }
    54     spfa(1);
    55     for(int i=1;i<=n;i++)printf("%d
    ",ans[i]);
    56     return 0;
    57 }

    思考:

    由这道题我们想到,如果对与任意一个有向无环且带权的图,需要输出规定原点到其它点的最短路径条数,这样应该怎么去做呢?

    我们可以先跑一遍spfa,再进行DAG+DP(或者记忆化搜索),也可以直接两遍spfa跑过(YZK大佬告诉我的方法,仔细想想思路都差不多,原理还是DP),于是乎,论DP的重要性,当然也可以看出spfa的应用有多广泛。。。

    推广题:POJ3463(解题报告)

  • 相关阅读:
    批处理学习总结之常用命令1
    Delphi常用数据类型
    Delphi预编译指令总结
    Delphi同步互斥总结
    MyEclipse 环境配置总结
    倒排索引
    laravel 学习相关笔记
    elasticsearch倒排索引原理
    原生sql和 TP sql怎么关联?
    elastic
  • 原文地址:https://www.cnblogs.com/five20/p/7782869.html
Copyright © 2011-2022 走看看