[题解](最短路)最短路点数

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≤50001≤v≤10000

注意:由于ab的最短路可能不止一条,所以所有可能出现在各种最短路上的点都要计入答案!!


 

考試題,當時想著和最短路計數一樣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);
    }
}

 

 

 

 

 

 

 

 

posted @ 2019-04-22 17:34  羊肉汤泡煎饼  阅读(254)  评论(0编辑  收藏  举报