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\n", dist[num - 1]);
59     else printf("-1\n");
60 }

Atcoder Snuke's Subway Trip 重构图

原文地址:https://www.cnblogs.com/unnamed05/p/9313257.html

时间: 2024-08-29 15:05:51

Atcoder Snuke's Subway Trip 重构图的相关文章

AtCoder ARC061E Snuke&#39;s Subway Trip 最短路

目录 Catalog Solution: (有任何问题欢迎留言或私聊 && 欢迎交流讨论哦 Catalog Problem:传送门 ?Portal ?原题目描述在最下面. ?\(n(1e5)\)个点, \(m(2e5)\)条边, 每条边有一个属性值.经过一条同一属性值的连续路径花费为1.问从1到n的最小花费. Solution: 我的解法 ?直接边最短路搞,然后t的飞起.仔细一想,这样写的话有\(1e5\)个点,边数更是多到飞起,拿命跑啊,不过代码我还是放下面. 正解:拆点 ?把一条\(u

【例题收藏】◇例题&#183;I◇ Snuke&#39;s Subway Trip

◇例题·I◇ Snuke's Subway Trip 题目来源:Atcoder Regular 061 E题(beta版) +传送门+ 一.解析 (1)最短路实现 由于在同一家公司的铁路上移动是不花费的,只有在换乘时会花费1日元.我们可以视换乘的花费为点权--当换乘到不同公司时花费1,同一家公司时花费0. 对于这种点权因情况而变化的题,最常见的做法便是拆点.设节点 u 相连的铁路由 c1,c2,...,cp p个公司修建,则将节点u拆分为节点 uc1~ucp,点uci表示到达点u的铁路是由公司c

[ARC061E]すぬけ君の地下鉄旅行 / Snuke&#39;s Subway Trip

题目大意:Snuke的城镇有地铁行驶,地铁线路图包括$N$个站点和$M$个地铁线.站点被从$1$到$N$的整数所标记,每条线路被一个公司所拥有,并且每个公司用彼此不同的整数来表示. 第$i$条线路($1\le i \le M$)是直接连接$p_i$与$q_i$的双向铁路,中间不存在其他站点,且这条铁路由$c_i$公司所拥有. 如果乘客只乘坐同一公司的铁路,他只需要花费一元,但如果更换其他公司的铁路需要再花一元.当然,如果你要再换回原来的公司,你还是要花一元. Snuke在1号站的位置出发,他想通

bzoj2407 探险 (重构图 + 最短路)

2407: 探险 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 148  Solved: 84[Submit][Status][Discuss] Description 探险家小T好高兴!X国要举办一次溶洞探险比赛,获奖者将得到丰厚奖品哦!小T虽然对奖品不感兴趣,但是这个大振名声的机会当然不能错过! 比赛即将开始,工作人员说明了这次比赛的规则:每个溶洞和其他某些溶洞有暗道相连.两个溶洞之间可能有多条道路,也有可能没有,但没有一条暗道直接从自己连到

csp退役前的做题计划1(真)

csp退役前的做题计划1(真) 因为我太菜了,所以在第一次月考就会退役,还是记录一下每天做了什么题目吧. 任务计划 [ ] Z算法(Z Algorithm) 9.28 [x] ARC061C たくさんの数式 / Many Formulas [x] ARC061D すぬけ君の塗り絵 / Snuke's Coloring [x] ARC061E すぬけ君の地下鉄旅行 / Snuke's Subway Trip [x] ARC061F 3人でカードゲーム / Card Game for Three [

外部排序&amp;多路归并排序

外部排序: 一.定义问题 外部排序指的是大文件的排序,即待排序的记录存储在外存储器上,待排序的文件无法一次装入内存,需要在内存和外部存储器之间进行多次数据交换,以达到排序 整个文件的目的.外部排序最常用的算法是多路归并排序,即将原文件分解成多个能够一次性装入内存的部分,分别把每一部分调入内存完成排序.然后,对已经排 序的子文件进行多路归并排序. 二.处理过程 (1)按可用内存的大小,把外存上含有n个记录的文件分成若干个长度为L的子文件,把这些子文件依次读入内存,并利用有效的内部排序方法对它们进行

【BZOJ-1924】所驼门王的宝藏 Tarjan缩点(+拓扑排序) + 拓扑图DP

1924: [Sdoi2010]所驼门王的宝藏 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 787  Solved: 318[Submit][Status][Discuss] Description Input 第一行给出三个正整数 N, R, C. 以下 N 行,每行给出一扇传送门的信息,包含三个正整数xi, yi, Ti,表示该传送门设在位于第 xi行第yi列的藏宝宫室,类型为 Ti.Ti是一个1~3间的整数, 1表示可以传送到第 xi行任意

2208: [Jsoi2010]连通数

2208: [Jsoi2010]连通数 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1371  Solved: 557[Submit][Status] Description Input 输入数据第一行是图顶点的数量,一个正整数N. 接下来N行,每行N个字符.第i行第j列的1表示顶点i到j有边,0则表示无边. Output 输出一行一个整数,表示该图的连通数. Sample Input 3 010 001 100 Sample Output 9

第一个GraphX程序

程序功能:收集顶点指向的邻居中所在地 /* * 找出每个顶点所指向的邻居中所在的地区 */ import org.apache.spark.SparkContext import org.apache.spark.SparkContext._ import org.apache.spark.SparkConf import scala.collection.mutable.Map import org.apache.spark._ import org.apache.spark.graphx._