Atcoder Snuke's Subway Trip 重构图
Posted unnamed05
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Atcoder Snuke's Subway Trip 重构图相关的知识,希望对你有一定的参考价值。
这题主要是重构图的方法很难思考。
方法一:考虑在每个公司意义下的联通块,每个联通块对应一个虚拟节点,联通块内的节点到联通块对应的虚拟节点有一条边,构建出一个二分图,跑一遍BFS,将经过的边数除以2。这里有两种实现, 细节都注释在了程序里
1 #include<bits/stdc++.h> 2 using namespace std; 3 vector<pair<int,int> > nei[1000005]; 4 vector<int> cit[1000005]; 5 vector<int>comp; 6 int col[1000005]; 7 bool vis[1000005]; 8 vector<int>newnei[1000005]; 9 int dp[1000005]; 10 int poi[1000005]; 11 queue<int> q; //无需跑最短路,直接写bfs,用queue 12 int main() 13 { 14 int n,m; 15 cin>>n>>m; 16 memset(col,-1,sizeof col); 17 for(int i=0;i<m;i++) 18 { 19 int x,y,c; 20 scanf("%d %d %d",&x,&y,&c); 21 x--,y--,c--; 22 nei[x].push_back(make_pair(c,y)); 23 nei[y].push_back(make_pair(c,x)); 24 cit[c].push_back(x); 25 cit[c].push_back(y); 26 comp.push_back(c); 27 } 28 sort(comp.begin(),comp.end()); 29 comp.erase(unique(comp.begin(),comp.end()),comp.end()); 30 for(int i=0;i<n;i++) 31 { 32 sort(nei[i].begin(),nei[i].end()); 33 } 34 int newci=n; 35 for(int i=0;i<comp.size();i++) 36 { 37 int cmp=comp[i]; 38 for(int j=0;j<cit[comp[i]].size();j++) 39 { 40 int v=cit[comp[i]][j]; 41 if(col[v]==cmp) continue; 42 q.push(v); 43 col[v]=cmp; 44 vector<int> ciin; 45 while(!q.empty()) 46 { 47 v=q.front(); 48 ciin.push_back(v); 49 q.pop(); 50 int k=0; 51 for(;poi[v]<nei[v].size();poi[v]++) //这里的poi[v]很好的利用了按公司编号从小到大的单调性 52 { 53 k=poi[v]; 54 if(nei[v][k].first!=cmp) break; 55 int u=nei[v][k].second; 56 if(col[u]==cmp) continue; 57 col[u]=cmp; 58 q.push(u); 59 } 60 } 61 for(int k=0;k<ciin.size();k++) 62 { 63 int v=ciin[k]; 64 newnei[v].push_back(newci); 65 newnei[newci].push_back(v); 66 } 67 newci++; 68 } 69 } 70 for(int i=0;i<newci;i++) dp[i]=-2; 71 dp[0]=1; 72 q.push(0); 73 while(!q.empty()) 74 { 75 int v=q.front(); 76 q.pop(); 77 for(int k=0;k<newnei[v].size();k++) 78 { 79 int u=newnei[v][k]; 80 if(dp[u]==-2) 81 { 82 dp[u]=dp[v]+1;q.push(u); 83 } 84 85 } 86 } 87 cout<<dp[n-1]/2; 88 }
1 #include<bits/stdc++.h> 2 using namespace std; 3 vector<pair<int,int> > nei[1000005],cit[1000005]; 4 vector<int>comp; 5 int vis[1000005]; 6 vector<int>newnei[1000005]; 7 int dp[1000005]; 8 int par[1000005]; 9 void init(int x) 10 { 11 par[x]=x; 12 } 13 int find(int x) 14 { 15 return (par[x]==x)?x:par[x]=find(par[x]); 16 } 17 void merge(int x,int y) 18 { 19 x=find(x);y=find(y); 20 par[x]=y; 21 } 22 queue<int> q; 23 int main() 24 { 25 int n,m; 26 cin>>n>>m; 27 for(int i=0;i<m;i++) 28 { 29 int x,y,c; 30 scanf("%d %d %d",&x,&y,&c); 31 x--,y--,c--; 32 cit[c].push_back(make_pair(x,y)); 33 comp.push_back(c); 34 } 35 sort(comp.begin(),comp.end()); 36 comp.erase(unique(comp.begin(),comp.end()),comp.end()); 37 int newci=n; 38 for(int i=0;i<comp.size();i++) 39 { 40 int cmp=comp[i]; 41 for(int j=0;j<cit[cmp].size();j++) 42 { 43 int v=cit[cmp][j].first,u=cit[cmp][j].second; 44 init(v);init(u); 45 vis[v]=vis[u]=0; //用到哪些就将哪些初始化 46 } 47 for(int j=0;j<cit[cmp].size();j++) 48 { 49 merge(cit[cmp][j].first,cit[cmp][j].second); 50 } 51 for(int j=0;j<cit[cmp].size();j++) 52 { 53 int v=cit[cmp][j].first; 54 v=find(v); 55 if(!vis[v]) 56 { 57 vis[v]=newci; 58 newnei[v].push_back(newci); 59 newnei[newci].push_back(v); 60 newci++; 61 } 62 if(!vis[cit[cmp][j].first]) 63 { 64 int u=cit[cmp][j].first; 65 newnei[vis[v]].push_back(u); 66 newnei[u].push_back(vis[v]); 67 vis[cit[cmp][j].first]=newci; 68 } 69 if(!vis[cit[cmp][j].second]) 70 { 71 int u=cit[cmp][j].second; 72 newnei[vis[v]].push_back(u); 73 newnei[u].push_back(vis[v]); 74 vis[cit[cmp][j].second]=newci; 75 } 76 } 77 } 78 for(int i=0;i<newci;i++) dp[i]=-2; 79 dp[0]=1; 80 q.push(0); 81 while(!q.empty()) 82 { 83 int v=q.front(); 84 q.pop(); 85 for(int k=0;k<newnei[v].size();k++) 86 { 87 int u=newnei[v][k]; 88 if(dp[u]==-2) 89 { 90 dp[u]=dp[v]+1;q.push(u); 91 } 92 } 93 } 94 cout<<dp[n-1]/2; 95 }
方法二:对于每个节点V,设置虚拟节点VC,VC到V有一条边,若边(U,V)是由公司C造的,则VC到UC有一条边,所以虚拟节点到其它节点的边权为0,真实节点到虚拟节点的边权为1,跑一遍最短路
1 #include<stdio.h> 2 #include<vector> 3 #include<algorithm> 4 #include<queue> 5 using namespace std; 6 typedef pair<int, int>pii; 7 typedef pair<pii, int>pi3; 8 vector<pii>pat[600000]; 9 bool flag[600000]; 10 int dist[600000]; 11 int main() 12 { 13 int num, way; 14 scanf("%d%d", &num, &way); 15 vector<pii>zat; 16 vector<pi3>zp; 17 for (int i = 0; i < way; i++) 18 { 19 int za, zb, zc; 20 scanf("%d%d%d", &za, &zb, &zc); 21 za--, zb--, zc--; 22 zat.push_back(make_pair(za, zc)); 23 zat.push_back(make_pair(zb, zc)); 24 zp.push_back(make_pair(make_pair(za, zb), zc)); 25 zp.push_back(make_pair(make_pair(zb, za), zc)); 26 } 27 sort(zat.begin(), zat.end()); 28 for (int i = 0; i < zat.size(); i++) 29 { 30 pat[num + i].push_back(make_pair(zat[i].first, 0)); 31 pat[zat[i].first].push_back(make_pair(num + i, 1)); 32 } 33 for (int i = 0; i < zp.size(); i++) 34 { 35 int l1 = lower_bound(zat.begin(), zat.end(), make_pair(zp[i].first.first, zp[i].second)) - zat.begin(); 36 int l2 = lower_bound(zat.begin(), zat.end(), make_pair(zp[i].first.second, zp[i].second)) - zat.begin(); 37 pat[l1 + num].push_back(make_pair(l2 + num, 0)); 38 } 39 priority_queue<pii>que; 40 que.push(make_pair(0, 0)); 41 fill(dist, dist + 600000, 1000000000); 42 for (;;) 43 { 44 if (que.empty())break; 45 pii z = que.top(); 46 que.pop(); 47 if (flag[z.second])continue; 48 flag[z.second] = true; 49 for (int i = 0; i < pat[z.second].size(); i++) 50 { 51 if (dist[pat[z.second][i].first]>-z.first + pat[z.second][i].second) 52 { 53 dist[pat[z.second][i].first] = -z.first + pat[z.second][i].second; 54 que.push(make_pair(-dist[pat[z.second][i].first], pat[z.second][i].first)); 55 } 56 } 57 } 58 if (flag[num - 1])printf("%d ", dist[num - 1]); 59 else printf("-1 "); 60 }
以上是关于Atcoder Snuke's Subway Trip 重构图的主要内容,如果未能解决你的问题,请参考以下文章
AtCoder ARC061E Snuke's Subway Trip 最短路
Cat Snuke and a Voyage AtCoder - 2660
例题收藏◇例题·I◇ Snuke's Subway Trip