题目大意:有N个点,两个人,其中一个人住在点1,另一个人住在点n
有M个点集,集合内的数表示任意两点的距离为dis
现在问,如果两个人要见面,需要最短距离是多少,有哪几个点能被当成见面点
解题思路:分别对两个点进行最短路,但是不能直接最短路,这里有一个问题是,边太多了
其实也不会很多,每个点集只能被松弛一次,因为里面所有的点已经是最短的状态了,理解这个就可以做了
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
typedef pair<ll,int> P;
#define INF 0x3f3f3f3f
int n,m;
vector<int>v[maxn],belong[maxn];
ll dis[maxn];
ll num[maxn];
ll d[2][maxn];
bool vis[maxn];
void dijstra(int s,int pos)
{
memset(d[pos],0x3f,sizeof(d[pos]));
priority_queue<P,vector<P>,greater<P> >q;
q.push(make_pair(0,s));
d[pos][s] = 0;
while(!q.empty())
{
P t = q.top();
q.pop();
int u = t.second;
if(d[pos][u] < t.first)
continue;
for(int i = 0; i < belong[u].size(); i ++)
{
int id = belong[u][i];
if(!vis[id]){
for(int j = 0; j < v[id].size(); j ++)
{
int vs = v[id][j];
if(d[pos][u] + dis[id] < d[pos][vs])
{
d[pos][vs] = d[pos][u] + dis[id];
q.push(make_pair(d[pos][vs],vs));
}
}
vis[id] = true;
}
}
}
}
int main()
{
int T;
scanf("%d",&T);
for(int ii = 1; ii <= T; ii ++)
{
for(int i = 1; i < maxn; i ++)
v[i].clear(),belong[i].clear();
scanf("%d%d",&n,&m);
for(int i = 1;i <= m;i ++)
{
scanf("%I64d%I64d",&dis[i],&num[i]);
for(int j = 1; j <= num[i]; j ++)
{
int x;
scanf("%d",&x);
v[i].push_back(x);
belong[x].push_back(i);
}
}
memset(vis,false,sizeof(vis));
dijstra(1,0);
memset(vis,false,sizeof(vis));
dijstra(n,1);
ll ans = INF;
for(int i = 1; i <= n; i ++)
{
ans = min(ans,max(d[0][i],d[1][i]));
}
printf("Case #%d: ",ii);
if(ans == INF)
{
puts("Evil John");
continue;
}
printf("%I64d\n",ans);
vector<int>an;
for(int i = 1; i <= n; i ++)
{
if(max(d[0][i],d[1][i]) == ans)
an.push_back(i);
}
for(int i = 0; i < an.size(); i ++)
{
printf("%d%c",an[i],i < an.size() - 1 ? ' ':'\n');
}
}
return 0;
}