Luogu 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。



第一眼看到這個題,不難想到先求出起點到所有點的最短路然後bfs,但是再看一眼數據範圍,顯然是不可行的。。。
那麼我們就從最短路那方面去考慮
SPFA就是bfs,而且在找到到一個點的最短路時會進行鬆弛操作
那麼我們不難想到,在每次鬆弛一個點時,可能就找到了到這個點的最短路
然後不難想到,這時到這個點的最短路的條數等於到前驅節點的最短路的條數
但是到這個點的所有最短路不一定只經過一個相同的前驅,那麼我們加一個條件,如果鬆弛的時候,到這個點的距離=到它的最短路的距離,那麼最短路的條數加上當前前驅節點的最短路的條數,差不多就是個記憶化
如果一個節點被鬆弛了,那說明它之前的路徑都不是最短路,直接賦值成前驅的最短路條數
然後還要mod 100003(我一開始居然就沒注意到,然後就只有60分。。。現在審題太粗了。。。)

其實總結一下,好像一些算法的中間過程可以再進一步的修飾然後就可以解決一些相關問題,比如逆序對和這個,以後說不定還會碰到其他的,如果多的話就再開一篇單獨列出


代碼

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <queue>
#define For(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
int read()
{
    char c;
    int a=0;
    bool t=0;
    while((c=getchar())==' '||c=='\n'||c=='\r');
    if(c=='-')
    {
        t=1;
        c=getchar();
    }
    while(isdigit(c))
    {
        a*=10;
        a+=(c-'0');
        c=getchar();
    }
    return a*(t?-1:1);
}
struct line{
    int to,next;
}edge[4000001];
int n,m,ans[1000001],last[1000001],dis[1000001];
bool vis[1000001];
void add(int from,int to,int i)
{
    edge[i].next=last[from];
    last[from]=i;
    edge[i].to=to;
}
void spfa()
{
    int tx;
    memset(dis,127,sizeof dis);
    queue<int> q;
    q.push(1);dis[1]=0;vis[1]=1;ans[1]=1;
    while(!q.empty())
    {
        tx=last[q.front()];
        while(tx)
        {
            if(dis[edge[tx].to]>dis[q.front()]+1)
            {
                dis[edge[tx].to]=dis[q.front()]+1;
                ans[edge[tx].to]=ans[q.front()];
                if(!vis[edge[tx].to])
                {
                    q.push(edge[tx].to);
                    vis[edge[tx].to]=1;
                }
            }
            else if(dis[edge[tx].to]==dis[q.front()]+1)
            {
                ans[edge[tx].to]+=ans[q.front()];
                ans[edge[tx].to]%=100003;
            }
            tx=edge[tx].next;
        }
        vis[q.front()]=0;
        q.pop();
    }
}
int main()
{
    int tx,ty;
    n=read();
    m=read();
    m+=m;
    For(i,1,m)
    {
        tx=read();
        ty=read();
        add(tx,ty,i++);
        add(ty,tx,i);
    }
    spfa();
    For(i,1,n)
     printf("%d\n",ans[i]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章