日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

【floyd】【bitset】洛谷 P1841 [JSOI2007]重要的城市 题解

發布時間:2023/12/20 javascript 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【floyd】【bitset】洛谷 P1841 [JSOI2007]重要的城市 题解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

? ??bitset玄學完美優化復雜度?

?

題目描述

參加jsoi冬令營的同學最近發現,由于南航校內修路截斷了原來通向計算中心的路,導致去的路程比原先增加了近一公里。而食堂門前施工雖然也截斷了原來通向計算中心的路,卻沒有使路程增加,因為可以找到同樣長度的路作替代。其實,問題的關鍵在于,路截斷的地方是交通要點。

?

同樣的情況也出現在城市間的交通中。某些城市如果出了問題,可能會引起其他很多城市的交通不便。另一些城市則影響不到別的城市的交通。jsoi冬令營的同學發現這是一個有趣的問題,于是決定研究這個問題。

?

他們認為這樣的城市是重要的:如果一個城市c被破壞后,存在兩個不同的城市a和b(a, b均不等于c),a到b的最短距離增長了(或不通),則城市c是重要的。

?

jsoi冬令營的同學面對著一張教練組交給他們的城市間交通圖,他們希望能找出所有重要的城市。現在就請你來解決這個問題。

?

輸入輸出格式

輸入格式:

第一行兩個整數N,M,N為城市數,M為道路數。

?

接下來M行,每行三個整數,表示兩個城市之間的無向邊,以及之間的路的長度。

?

輸出格式:

一行,按遞增次序輸出若干的數,表示重要的城市。

?

如果沒有點的話需要輸出一行

“No important cities.”

去掉引號。

?

輸入輸出樣例

輸入樣例#1:

4 4 1 2 1 2 3 1 4 1 2 4 3 2

輸出樣例#1:

2

說明

30%的數據:$N\le 20$;

?

60%的數據:$N\le 100$;

?

100%的數據:$N\le 200,M\le \frac{N\times (N-1)}{2},0<c\le 10000$。$c$即路的長度。

?

保證不出現重邊和自環

?

感謝@趙昕鵬 和@qq2477259579 提供程序

?

題解:

? ??因為Floyd是一種玄學DP思想,所以它的狀態更新來源有很多,在這個題里需要整理出它的階段性與轉移,看上去十分麻煩。而我們如果把Floyd當作最短路算法中的松弛,就是相當于在把兩段最短路拼接在一起,擁有它們合在一起的性質。

?

重要城市

? ??重要城市就是如果這個點被刪掉,那么最短路的長度就會改變。因此這個點一定在最短路上。而當兩點間的最短路有多條時,它們上的點不一定都是重要城市,經過分析我們可以這樣理解:設$(u,v)$間最短路條數為$k$,重要城市為$p$,那么這$k$條最短路一定都經過點$p$。用反例來說明,就是如果不是$k$條最短路都經過點$p$,那么去掉點$p$,還有剩下的最短路可以走,則不合法。

?

? ??因此我們可以開一個三維數組$im[i][j][k]$表示k在$latex i,j$的幾條最短路上。而我們用floyd做最短路計數也比較方便,一旦$k$所在的最短路數量與$(i,j)$間的最短路數量相同,那么$k$就一定是一個重要城市,判斷條件為$im[i][j][k]==cnt[i][j]\Rightarrow k$是重要城市。

? ??在上圖中,1→8最短路計數為3,其中除了起點和終點,被經過了3次的點的點有2和7,因此它們是這條路徑上的重要城市。

?

? ??因為floyd的時間復雜度為$O(N^3)$,而每次更新還要循環一個$N$,因此總時間復雜度為$O(N^4)$。

?

bitset優化

? ??我們在上面提到,狀態合并/更新需要額外枚舉一個$O(N)$,我們可不可以把這個$N$省掉,或者說優化一點呢?

?

? ??這時可以考慮bitset,bitset可以使常數優化32倍,這個題的$latex N$規模才200,優化一個32就快把一個$N$變成一個$\log N$了,這個題的數據規模還是可以承受的。不過bitset存的是二進制啊,可是上面提到的數組存的是計數啊。

?

? ??我們可以換一個方式想想,如果這兩個點之間已經找到了4條最短路,其中有3條經過點$p$,那此時$p$已經不合法了,就直接把它置為0,以后盡管所有路徑都經過$p$,它也不可能是關鍵城市。

?

? ??因此bitset中im[i][j][k]里面存的是,現有狀態下,k是不是i到j最短路上的關鍵城市。當更新(松弛)最短路時,關鍵城市是兩段最短路上的關鍵城市之并集;而更新最短路計數,也就是找到了一條新的最短路時,如上圖,就要取交集,因為一個城市只有在兩點間任何一條最短路上都存在,才能作為這兩點間的關鍵城市。而交集并集在位運算中就是and(&)和or(|),而點集有200,普通的位運算完成不了,就讓bitset來做。

?

? ??在一開始初始化時,把兩個連接在一起的點上的關鍵城市設為兩個端點,在floyd“松弛”最短路時,直接把兩段最短路的關鍵城市“拼起來”,就是新的最短路上的關鍵城市。最后判斷用$O(N^3)$遍歷,看一個點是否為某兩個點之間的關鍵城市,不過要注意不能與這兩個點重合,因為為了方便,一開始我們把起點和終點也定為關鍵城市(符合關鍵城市的一般定義)。

?

? ??因此這道題的總復雜度為$O(\frac{N^4}{32}+N^3)$

?

Code:

#include<cstdio> #include<cstring> #include<bitset> using std::bitset; bitset<210> im[210][210]; int f[210][210]; int is[210]; int main() {memset(f,0x3f,sizeof(f));int u,v,n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)f[i][i]=0;for(int i=1;i<=m;i++){scanf("%d%d",&u,&v);scanf("%d",&f[u][v]);f[v][u]=f[u][v];}for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){im[i][j][i]=1;//初始化設兩端為重要城市im[i][j][j]=1;}for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(f[i][k]+f[k][j]==f[i][j])im[i][j]&=(im[i][k]|im[k][j]);//當更新計數時取交集else if(f[i][k]+f[k][j]<f[i][j])//當更新最短路時直接賦值為兩段的并集{f[i][j]=f[i][k]+f[k][j];im[i][j]=im[i][k]|im[k][j];}for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)for(int k=1;k<=n;k++)if(k!=i&&k!=j)//注意特判if(im[i][j][k])is[k]=1;int flag=0;for(int i=1;i<=n;i++)if(is[i]){flag=1;printf("%d ",i);}if(!flag)//注意判斷無解puts("No important cities.");return 0; }

  

轉載于:https://www.cnblogs.com/wjyyy/p/lg1841.html

總結

以上是生活随笔為你收集整理的【floyd】【bitset】洛谷 P1841 [JSOI2007]重要的城市 题解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。