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 }

 

还有一种很自然的构图方法:对于每个节点,用map<pair<v,col>,cost>来记录,直接暴力转移。由于这样会使边数太多,所以对每个节点再设一个虚拟节点(v,0),所有(v,col)都有一条连向(v,0),边权为1的边

 1 #include<bits/stdc++.h>
 2 //#include<unordered_map>
 3 using namespace std;
 4 map<int,vector<int> >  nei[100005];
 5 map<int,int> dp[100005];
 6 vector<pair<int,int> >alnei[100005];
 7 struct Node
 8 {
 9     int cost,color,v;
10     Node (int cos,int col,int u)
11     {
12         cost=cos;
13         color=col;
14         v=u;
15     }
16     bool operator <(Node a) const
17     {
18         return cost>a.cost;
19     }
20 };
21 int main()
22 {
23     int n,m;
24     cin>>n>>m;
25     for(int i=0;i<m;i++)
26     {
27         int x,y,z;
28         cin>>x>>y>>z;
29         x--,y--;
30         nei[x][z].push_back(y);
31         nei[y][z].push_back(x);
32         alnei[x].push_back(make_pair(y,z));
33         alnei[y].push_back(make_pair(x,z));
34     }
35     priority_queue<Node> q;
36     q.push(Node(0,0,0));
37     while(!q.empty())
38     {
39         Node tmp=q.top();
40         q.pop();
41         int v=tmp.v,cost=tmp.cost,col=tmp.color;
42         if(dp[v][col]!=cost) continue;
43         if(dp[v].find(0)==dp[v].end()||dp[v][0]>cost)
44         {
45             dp[v][0]=cost;
46             q.push(Node(cost,0,v));
47         }
48         if(col==0)
49         {
50             for(int i=0;i<alnei[v].size();i++)
51             {
52                 int u=alnei[v][i].first,colu=alnei[v][i].second;
53                 if(dp[u].find(colu)==dp[u].end()||dp[u][colu]>cost+1)
54                 {
55                     dp[u][colu]=cost+1;
56                     q.push(Node(cost+1,colu,u));
57                 }
58             }
59             continue;
60         }
61         for(int i=0;i<nei[v][col].size();i++)
62         {
63             int u=nei[v][col][i],colu=col;
64             if(dp[u].find(colu)==dp[u].end()||dp[u][colu]>cost)
65             {
66                 dp[u][colu]=cost;
67                 q.push(Node(cost,colu,u));
68             }
69         }
70     }
71     int mi=1e9;
72     for(map<int,int>::iterator it=dp[n-1].begin();it!=dp[n-1].end();it++)
73     {
74         mi=min(it->second,mi);
75     }
76     if(mi==1e9) cout<<-1; else cout<<mi;
77 }

 

posted @ 2018-07-15 12:43  双零  阅读(218)  评论(0)    收藏  举报