標籤:
題目描述
Description
某首都城市的商人要經常到各城鎮去做生意,他們按自己的路線去做,目的是為了更好的節約時間。
假設有N個城鎮,首都編號為1,商人從首都出發,其他各城鎮之間都有道路串連,任意兩個城鎮之間如果有直連道路,在他們之間行駛需要花費單位時間。該國公路網路發達,從首都出發能到達任意一個城鎮,並且公路網路不會存在環。
你的任務是協助該商人計算一下他的最短旅行時間。
枯燥無味的直接發代碼的話,我自己都看不下去,所以我決定講講做法,實在做不出來的,再抄我下面的代碼吧;
首先我們應該Crowdsourced Security Testing道怎麼解,路線如下:
1-->3-->2-->5 而n可以達到30000,如果每個點都用spfa求最短距離然後再累加的話,肯定逾時
因為圖中沒有存在環,所以肯定兩點之間只存在一條路線,用lca做就妥妥過了(如果可以也能用線段樹過,會的來教一下我)
也就是說,只要求出1->1(求1->1是怕資料有開始第一個點不是到達1的),1->3,3->2,2->5的最近公用祖先,然後求每對頂點都最近公用祖先的距離和即可算出;
如果聽不大懂沒關係,我下面稍微類比一下範例吧
1
/ \
2 5
/ \
3 4
圖在上面
1.先用bfs算一次頂點1到各個頂點的距離,用dis數組表示:
1 2 3 4 5
dis 0 1 2 2 1
求這個距離的用處,例如:2和5的最近公用祖先為1,而2到5的距離就是dis[2]-dis[1]+dis[5]-dis[1]=(dis[2]+dis[5])-2*dis[1]=2,就是2到公用祖先的距離加上5到公用祖先的距離
2.然後lca的做法自己百度吧,算出1--1,1--3,3--2,2--5的公用祖先,剛好都是1(,,,,)然後算出(dis[1]+dis[1])-2*dis[1]+(dis[1]+dis[3])-2*dis[1]+(dis[3]+dis[2])-2*dis[1]+(dis[2]+dis[5])-2*dis[1] 就是答案了
最後,還有不懂的聯絡[email protected],也歡迎來糾正錯誤,更歡迎希望神犇來帶我飛
codevs上的同個題解也是我寫的,就不要懷疑我抄襲了:)
1 #include <cstdio> 2 #include <iostream> 3 #include <vector> 4 #include <queue> 5 #include <cstring> 6 using namespace std; 7 const int _maxn=30010; 8 vector<int> a[_maxn]; 9 vector<int> t[_maxn]; 10 queue<int> que; 11 int dis[_maxn],n,m,f[_maxn]; 12 bool vis[_maxn]; 13 struct question 14 { 15 int u,v,ans; 16 }b[_maxn]; 17 void read() 18 { 19 int i,x,y; 20 scanf("%d",&n); 21 for(i=1;i<n;i++) 22 { 23 f[i]=i; 24 scanf("%d%d",&x,&y); 25 a[x].push_back(y); 26 a[y].push_back(x); 27 } 28 f[n]=n; 29 scanf("%d",&m); 30 b[1].u=1; 31 for(i=1;i<=m;i++) 32 { 33 scanf("%d",&x); 34 b[i].v=x; 35 t[x].push_back(i); 36 if(i+1<=m) 37 { 38 b[i+1].u=x; 39 t[x].push_back(i+1); 40 } 41 } 42 } 43 int find(int x) 44 { 45 return f[x]==x?x:find(f[x]); 46 } 47 void lca(int x,int fa) 48 { 49 int l=a[x].size(),i,to; 50 for(i=0;i<l;i++) 51 { 52 to=a[x][i]; 53 if(to==fa) 54 continue; 55 lca(to,x); 56 f[to]=x; 57 vis[to]=true; 58 } 59 l=t[x].size(); 60 int xx,yy,zz; 61 for(i=0;i<l;i++) 62 { 63 to=t[x][i]; 64 xx=b[to].u; 65 yy=b[to].v; 66 if(xx==yy) 67 b[to].ans=xx; 68 if(xx!=x && yy==x && vis[xx]) 69 b[to].ans=find(xx); 70 if(xx==x && yy!=x && vis[yy]) 71 b[to].ans=find(yy); 72 } 73 } 74 void bfs() 75 { 76 memset(vis,false,sizeof(vis)); 77 que.push(1); 78 vis[1]=true; 79 dis[1]=0; 80 int i,l,from,to; 81 while(!que.empty()) 82 { 83 from=que.front(); 84 que.pop(); 85 l=a[from].size(); 86 for(i=0;i<l;i++) 87 { 88 to=a[from][i]; 89 if(!vis[to]) 90 { 91 dis[to]=dis[from]+1; 92 vis[to]=true; 93 que.push(to); 94 } 95 } 96 } 97 } 98 int clac_ans() 99 {100 int x,y,z,sum=0;101 for(int i=1;i<=m;i++)102 {103 x=b[i].u;104 y=b[i].v;105 z=b[i].ans;106 sum=sum+(dis[x]+dis[y])-(dis[z]<<1);107 }108 return sum;109 }110 void work()111 {112 bfs();113 memset(vis,false,sizeof(vis));114 lca(1,1);115 printf("%d\n",clac_ans());116 }117 int main()118 {119 read();120 work();121 return 0;122 }
codevs1036
codevs1036商務旅行