洛谷Oj-P1144 最短路計數-Dijkstra + 遞推
阿新 • • 發佈:2018-11-26
問題描述:
給出一個N個頂點M條邊的無向無權圖,頂點編號為1~N。問從頂點1開始,到其他每個點的最短路有幾條。
AC程式碼:
typedef pair<int,int> Pair;//到源點的距離、頂點編號
priority_queue<Pair,vector<Pair>,greater<Pair> > pq;//小頂堆
struct edge
{
int to;
int next;
int w;
};
edge e[2000010];
int head[1000010];
int id = 1;
int n,m;
int dis[1000010 ];//距離
int cnt[1000010];//cnt[i]表示從源點到頂點i的最短路的條數
void add_edge(int u,int v,int w)
{
e[id].to = v;
e[id].next = head[u];
e[id].w = w;
head[u] = id;
id++;
}
void dijkstra(int s)//堆優化
{
memset(dis,0x3F,sizeof(dis));//初始化
dis[s] = 0;//初始化
cnt[1] = 1;//遞推邊界
pq.push(make_pair(dis[s],s));//將源點入堆
while(!pq.empty())
{
int v = pq.top().second;
pq.pop();
for(int i = head[v]; i != -1; i = e[i].next)
{
int to = e[i].to;
int w = e[i].w;
if(dis[to] == dis[v] + w)//如果和當前的最短路長度相等
cnt[to] = (cnt[to] + cnt[v]) % Mod;//則加上cnt[中轉點v]
if(dis[to] > dis[v] + w)//如果比當前的最短路還要短
{
dis[to] = dis[v] + w;//更新
cnt[to] = 0;//置0
cnt[to] = (cnt[to] + cnt[v]) % Mod;//加上cnt[中轉點v]
pq.push(make_pair(dis[to],to));//因為dis[to]被鬆弛了,再入堆
}
}
}
return;
}
int main()
{
cin >> n >> m;
memset(head,-1,sizeof(head));//初始化
for(int i = 1; i <= m; ++i)
{
int a,b;
scanf("%d%d",&a,&b);
if(a == b)//去掉自環
continue;
add_edge(a,b,1);
add_edge(b,a,1);
}
dijkstra(1);
for(int i = 1; i <= n; ++i)
cout << cnt[i] << endl;
return 0;
}
解決方法:
因為路徑的長度都是1,考慮用鄰接矩陣的冪次去做,逐次累乘,判斷是否可達,答案為第一次可達時的
再就是考慮用最短路演算法,比如Dijkstra去做(為了跑得快一點,加了堆優化),然後在用中轉點鬆弛這一步上做文章,被鬆弛了說明要推翻之前的最短路條數,恰好相等則要加上,就這樣遞推。對於每一箇中轉點來說,它到源點的路徑長度已經是最短的了,不會再被鬆弛,最短路的條數也確定了。