1. 程式人生 > >洛谷——P1144 最短路計數

洛谷——P1144 最短路計數

lin can 初始化 onclick 初始 () clas har 變形

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。

變形的spfa(說白了就是一個bfs),在進行最短路查詢的時候判斷是否出現了距離相同的路徑。

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include
<algorithm> #define N 2000000 #define mod 100003 using namespace std; queue<int>q; bool vis[N]; int n,m,x,y,tot,head[N],ans[N],dis[N]; int read() { int x=0,f=1; char ch=getchar(); while(ch<0||ch>9){if(ch==-)f=-1; ch=getchar();} while(ch>=0&&ch<=9){x=x*10
+ch-0; ch=getchar();} return x*f; } struct Edge { int to,next,from; }edge[N<<1]; int add(int x,int y) { tot++; edge[tot].to=y; edge[tot].next=head[x]; head[x]=tot; } int main() { n=read(),m=read(); for(int i=1;i<=m;i++) x=read(),y=read(),add(x,y),add(y,x); memset(dis,0x3f3f3f3f,sizeof(dis)); q.push(1),dis[1]=0,vis[1]=true;ans[1]=1; while(!q.empty()) { x=q.front();q.pop();vis[x]=false; for(int i=head[x];i;i=edge[i].next) { int to=edge[i].to; if(dis[to]>dis[x]+1) { dis[to]=dis[x]+1; ans[to]=ans[x]%mod; if(!vis[to]) { vis[to]=true; q.push(to); } } else if(dis[to]==dis[x]+1) { ans[to]=(ans[x]+ans[to])%mod; if(!vis[to]) { vis[to]=true; q.push(to); } } } } for(int i=1;i<=n;i++) printf("%d\n",ans[i]); return 0; }
技術分享
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstdlib>
using namespace std;
struct Edge//鄰接表存邊
{
    int t;
    int nexty;
}edge[3000000];
int head[2000000]={0};//鄰接表的東東(存以i為發出點的編號最大的邊的編號)……有人不懂嗎
int cnt=0;
inline void add(int a,int b)//鄰接表添加邊
{
    cnt++;
    edge[cnt].t=b;
    edge[cnt].nexty=head[a];
    head[a]=cnt;
}
int js[2000000]={0};//每一個點的最短路徑條數
int rdjs[2000000]={0};//用來避免重復的統計表,存當前在隊列中,到節點i的最短路徑條數
int dis[2000000];//存最短路徑
bool in[2000000]={0};//是否在隊列中
queue<int>spfa;//SPFA所用隊列
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    int a,b;
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&a,&b);
        add(a,b);
        add(b,a);//存邊
    }
    for(int i=1;i<=n;i++)dis[i]=2e9;
    dis[1]=0;//初始化dis
    in[1]=true;
    js[1]=1;//1到1最短路徑1條
    rdjs[1]=1;//此次隊列中,到1的最短路徑條數為1
    spfa.push(1);//將1加入隊列
    int curr;
    while(!spfa.empty())
    {
        curr=spfa.front();//更新發出點
        for(int i=head[curr];i!=0;i=edge[i].nexty)//遍歷出發邊
        {
            if(dis[edge[i].t]>dis[curr]+1)//若最短路有變
            {
                dis[edge[i].t]=dis[curr]+1;//更新最短路
                rdjs[edge[i].t]=js[edge[i].t]=rdjs[curr]%100003;//以前的計數均舍棄,更新到出發點的到達路徑條數
                if(!in[edge[i].t])
                {//加入隊列

                    in[edge[i].t]=true;
                    spfa.push(edge[i].t);
                }
            }
            else
            if(dis[edge[i].t]==dis[curr]+1)//若又有一條最短路
            {
                js[edge[i].t]=(js[edge[i].t]+rdjs[curr])%100003;//增加最短路個數
                rdjs[edge[i].t]=(rdjs[edge[i].t]+rdjs[curr])%100003;//在rdjs上更新,避免重復
                if(!in[edge[i].t])
                {//入隊
                    in[edge[i].t]=true;
                    spfa.push(edge[i].t);
                }
            }
        }
        in[curr]=false;
        rdjs[curr]=0;//此次的最短路統計已用完,將此節點的最短路條數初始化,避免重復(在此題中似乎並沒有什麽用)
        spfa.pop();//出隊
    }
    for(int i=1;i<=n;i++)printf("%d\n",js[i]);//輸出
    return 0;
}
比較詳細一點的題解

洛谷——P1144 最短路計數