洛谷P1144 最短路计数 及其引申思考
图论题目练得比较少,发一道spfa的板子题目~
题目:P1144
题目描述
给出一个N个顶点M条边的无向无权图,顶点编号为1~N。问从顶点1开始,到其他每个点的最短路有几条。
输入输出格式
输入格式:输入第一行包含2个正整数N,M,为图的顶点数与边数。
接下来M行,每行两个正整数x, y,表示有一条顶点x连向顶点y的边,请注意可能有自环与重边。
输出格式:输出包括N行,每行一个非负整数,第i行输出从顶点1到顶点i有多少条不同的最短路,由于答案有可能会很大,你只需要输出mod 100003后的结果即可。如果无法到达顶点i则输出0。
输入输出样例
5 7
1 2
1 3
2 4
3 4
2 3
4 5
4 5
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\n",ans[i]); 56 return 0; 57 }
思考:
由这道题我们想到,如果对与任意一个有向无环且带权的图,需要输出规定原点到其它点的最短路径条数,这样应该怎么去做呢?
我们可以先跑一遍spfa,再进行DAG+DP(或者记忆化搜索),也可以直接两遍spfa跑过(YZK大佬告诉我的方法,仔细想想思路都差不多,原理还是DP),于是乎,论DP的重要性,当然也可以看出spfa的应用有多广泛。。。
推广题:POJ3463(解题报告)