Inspire:将思路理清,将难点抛离出来,将问题抽象化,再思考解决方法。
Analysis:最短路问题,难在建图。如果用邻接矩阵,边太多了,而点的个数我们可以接受,仔细读题发现,给出的集合内的任意的两个点的距离都是一定的,于是每个集合构造一个新的点作为中转站,集合内的点都连接两条线到该点,进来再出去,为了防止/2得到浮点数,所以进边和出边的权值都是t,最后结果/2。然后spfa搜两遍最短路,每个点的最大值作为两人在该点约会所需的时间,所有点中最小值即答案。
Note:需要初始化的变量(如pre[]、dis[])以及标志标量(如visted[])等,都要及时清零(改变),并注意清零的位置放在哪。
//哪些变量需要初始化,需要在哪个位置初始化,莫忘!仔细检查!
#include <iostream>
#include <stdio.h>
#include <queue>
#include <set>
#include <vector>
#include <math.h>
#include <algorithm>
#include <string.h>
using namespace std;
typedef long long ll;
const int maxn=(1e6+10);
const ll MAXN=1e17;
ll dis1[maxn];
ll dis2[maxn];
int n,m;
int cnt=0;
int cur_set;
int pre[maxn];
int visted[maxn];
struct Edge{
int u,v,w;
int next;
Edge(int u,int v,int w){
this->u=u;this->v=v;this->w=w;
}
Edge(){}
}edge[maxn<<1];
void Add(int u,int v,int w){
edge[cnt]=Edge(u,v,w);
edge[cnt].next=pre[u];
pre[u]=cnt++;
}
void Spfa(int x,ll dis[]){
queue<int> que;
que.push(x);
visted[x]=1;
for(int i=1;i<=cur_set;i++){
dis[i]=MAXN;
visted[i]=0;
}
dis[x]=0;
while(!que.empty()){
int u=que.front();
que.pop();
visted[u]=0;
int v,w;
for(int i=pre[u];~i;i=edge[i].next){
v=edge[i].v;
w=edge[i].w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
if(!visted[v]){
que.push(v);
visted[v]=1;//不要忘啊!!
}
}
}
}
}
int main()
{
int tt;
scanf("%d",&tt);
int kk=1;
int t,num,x;
while(tt--){
scanf("%d%d",&n,&m);
cur_set=n;
cnt=0;
memset(pre,-1,sizeof(pre));//要放在建图前,要全部初始化而不等cur_set
for(int i=1;i<=m;i++){
scanf("%d%d",&t,&num);
cur_set++;
for(int j=1;j<=num;j++){
scanf("%d",&x);
Add(x,cur_set,t);
Add(cur_set,x,t);
}
}
//错误位置:
//for(int i=1;i<=cur_set;i++){
//pre[i]=-1;
///visted[i]=0; visted[i]放在这初始化就错了,因为两个dis[]
// }
Spfa(1,dis1);
Spfa(n,dis2);
vector<int> vec;
//set<int> sset;set存储速度好像不如用vector然后最后sort一下
ll minn=MAXN;
for(int i=1;i<=n;i++){
minn=min(minn,max(dis1[i],dis2[i]));
}
for(int i=1;i<=n;i++){
if(minn==max(dis1[i],dis2[i])) vec.push_back(i);
//sset.insert(i);
}
if(minn==MAXN){
cout<<"Case #"<<kk++<<": "<<"Evil John"<<endl;
}
else{
cout<<"Case #"<<kk++<<": "<<minn/2<<endl;
//用set时的输出:
/*
set<int>::iterator it=sset.begin();
cout<<*it;
it++;
for(;it!=sset.end();it++){
cout<<" "<<*it;
}
cout<<endl;
*/
//另一种比较方便的写法:虽然比cout慢几百ms,但是在时限为几千ms的题来说问题不大
/*
sort(vec.begin(),vec.end());
for(int i=0;i<vec.size();i++){
printf("%d%c",vec[i],i==vec.size()-1?'\n':' ');
}
*/
sort(vec.begin(),vec.end());
cout<<vec[0];
for(int i=1;i<vec.size();i++){
cout<<" "<<vec[i];
}
cout<<endl;
}
}
}