P2510 -- The Number of Points in Shortest Path
时间限制:1000MS 内存限制:131072KB路 无 无
题目描述(points.cpp)
一张图有n个点,由m条带权无向边构成。对于两个点a,b你需要求出所有可能出现在a,b间最短路径上的点(包括a,b)
输入格式(points.in)
第一行n,m表示n个点,m条边
接下来m行,每行3个数a,b,v表示a,b之间有条边权为v的边
接下来一个数q,表示询问的个数
接下来q行,每行两个数a,b,表示询问a,b
输出格式(points.out)
对于每个询问,输出a,b之间最短路径上的点的总个数
样例输入
5 6
1 2 1
1 3 1
2 3 1
2 4 1
3 5 1
4 5 1
3
2 5
5 1
2 4
样例输出
4
3
2
数据规模与约定
对于10%的数据,n≤10,
对于50%的数据,n≤100,
对于所有的数据,n≤1000,m≤min(n⋅n/2,10000),q≤5000,1≤v≤10000
注意:由于a到b的最短路可能不止一条,所以所有可能出现在各种最短路上的点都要计入答案!!
考試題,當時想著和最短路計數一樣dp來著,結果哦顯然掛了,雖然我還是覺得dp也行
其實最暴力的方法應該是Floyd,對於每個詢問ans=sigma(d[a][k]+d[k][b]==d[a][b]) (1<=k<=n)
但是卡不過,於是對每個點跑一個spfa,複雜度O(km),k為2~3,所以可以卡過
#include<bits/stdc++.h> using namespace std; const int maxn=1010; const int maxm=10010; int n,m,qq; int d[maxn][maxn],v[maxn]; struct node{ int v,w,nxt; }e[maxm*2]; int head[maxn],cnt; void add(int u,int v,int w){ e[++cnt].v=v;e[cnt].w=w;e[cnt].nxt=head[u];head[u]=cnt; } void floyd(){ for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) d[i][j]=min(d[i][j],d[i][k]+d[k][j]); } void spfa(int s){ memset(v,0,sizeof(v)); queue<int>q; d[s][s]=0;v[s]=1;q.push(s); while(!q.empty()){ int x=q.front();q.pop();v[x]=0; for(int i=head[x];i;i=e[i].nxt){ int y=e[i].v,z=e[i].w; if(d[s][y]>d[s][x]+z){ d[s][y]=d[s][x]+z; if(!v[y])q.push(y),v[y]=1; } } } } int main() { scanf("%d%d",&n,&m); memset(d,0x3f,sizeof(d)); for(int i=1,u,v,w;i<=m;i++){ scanf("%d%d%d",&u,&v,&w); add(u,v,w);add(v,u,w); } for(int i=1;i<=n;i++)spfa(i); scanf("%d",&qq); for(int i=1,a,b;i<=qq;i++){ scanf("%d%d",&a,&b); int ans=0; for(int j=1;j<=n;j++) if(d[a][j]+d[j][b]==d[a][b])ans++; printf("%d\n",ans); } }