这题还是再考最短路算法,在这里还是迪杰斯特拉。
但难点在于建图,在这里将同一种种类的传送门具化成一个点,拥有这个传送门的可以通过这个传送门进行到达。但在花费上是二倍。
还有就是不要使用map<pair<int,int>,int>来保存边。这个数据类型操作会导致这道题超时。。。。。。
//要移动到同一点
//每个点上有一些传送门
//计算1到每个点的最短路和n到每个点的最短路。然后遍历每个点将两个最短路相加求最小的结果
//那么问题就是如何计算最短路。
//每个点都有附属的一些传送门。计算传送门之间的最短路然后让每个点来认领就行。
//什么狗屁附属,不同的传送门其实就是不同点之间的连线,但这连线也会产生重复的,重复的去取最短的那一个即可。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 2000010;
struct sy{
int to;
int next;
int w;
} edge[2000010];
int head[2000010];
struct Node{
int number;
int len;
bool operator < (const Node& n) const
{
return len>n.len;
}
};
priority_queue<Node> pq;
int n, m;
int cnt = 0;
int vis[maxn];
void add_edge(int x, int y, int w)
{
edge[++cnt].next = head[x];
edge[cnt].to = y;
edge[cnt].w = w;
head[x] = cnt;
}
void Dijkstra(int bg, int ans[])
{
memset(vis, 0, sizeof(vis));
memset(ans, 127, sizeof(vis));
pq.push({bg, 0});
ans[bg] = 0;
while (pq.size())
{
int number = pq.top().number;
pq.pop();
// cout<<"number="<<number<<" head[number]="<<ans[number]<<endl;
if (vis[number]) continue;
vis[number] = true;
for (int i=head[number];i;i = edge[i].next)
{
int next = edge[i].to;
int w = edge[i].w;
// cout<<"next="<<next<<endl;
// cout<<ans[number]+w<<" "<<ans[next]<<endl;
if (ans[number]+w<ans[next])
{
ans[next] = ans[number]+w;
pq.push({next, ans[next]});
}
}
}
}
signed main()
{
cin>>n>>m;
for (int i=1;i<=m;i++)
{
int t, s, x;
cin>>t>>s;
for (int j=1;j<=s;j++)
{
cin>>x;
add_edge(i+100000, x, t);
add_edge(x, i+100000, t);
}
}
//接着使用迪杰斯特拉算法求最短路
int ans_one[maxn];
int ans_n[maxn];
Dijkstra(1, ans_one);
Dijkstra(n, ans_n);
int ans = INT_MAX;
//遍历所有的点
for (int i=1;i<=n;i++)
{
// cout<<ans_one[i]<<' '<<ans_n[i]<<endl;
ans = min(ans, max(ans_one[i],ans_n[i]));
}
vector<int> vt;
//找点
for (int i=1;i<=n;i++)
{
if (max(ans_one[i],ans_n[i])==ans) vt.push_back(i);
}
if (ans>=2139062143)
{
cout<<-1<<endl;
return 0;
}
cout<<ans/2<<endl;
vector<int>::iterator vit;
for (vit = vt.begin();vit!=vt.end();vit++)
{
cout<<(*vit)<<' ';
}
return 0;
}

京公网安备 11010502036488号