题目:
一天zjx想和她的长老一起去百盛看电影。然而zjx在21b573而长老在天美,因此他们想先集合然后一起出发去百盛。因为他们很恩爱所以他们想尽快和彼此会和。现给出一张有n个点的图,(zjx和长老可以在这n个任意一个点中会和),规定1为21b573,n为天美。现在有m种传送阵,分布在各个点上,每个相同的传送阵可以相互传送,但需要花费ti分钟。
问zjx和长老需要花费多长时间才能见到面。
Input
第一行输入一个整数T(1<=T<=6),表示样例数。紧接着T行
第一行输入两个整数n,m(2<=n<=10^5).之后紧接着m行代表每种传送阵
每行包括两个整数ti(1<=ti<=10^9),si。ti表示在这种传送阵中传送需要消耗ti时间,
si表示这种传送阵分布在si个地方,紧跟着输入si个数来表示该传送阵所处的点编号。
保证si的和小于等于10^6.
Output
对于每一组样例,如果他们不能会和,则输出一行"Evil John"(没有引号)
如果能,则输出两行,第一行一个整数代表他们需要花费的时间
第二行代表他们可能相聚的地点。如果有多种可能,以一个递增序列将他们全输出出来
样例
Input
5 4
1 3 1 2 3
2 2 3 4
10 2 1 5
3 3 3 4 5
3 1
1 2 1 2
Output
Case #1: 3
3 4
Case #2: Evil John
Hint
In the first case, it will take Bessie 1 minute travelling to the 3rd block, and it will take Elsie 3 minutes travelling to the 3rd block. It will take Bessie 3 minutes travelling to the 4th block, and it will take Elsie 3 minutes travelling to the 4th block. In the second case, it is impossible for them to meet.
思路
建图
对于一些建图的问题,是集合式的,比如给ai个点,并且说这ai个点互相到达的距离为w,但是ai^2的时间建图是不可能的的,可以开一个中间节点建图,一种是 将所有ai连一条单向边到s ,边权为0,再由s向每个ai连一条单向边 ,边权为w。还有一种是所有节点都向s连一条无向边,边权为w/2;其实只要是连向中间节点的边权和连出来的的边权之和等于w即可。
针对这道题
从起点跑一遍最短路,再从终点跑一遍最短路,然后到每个节点的相遇最小时间即为ans[i]=max(dis[s][i],dis[t][i]);
代码
#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define maxm 1000005
#define maxn 200005
#define INF 0x3f3f3f3f
#define ll long long
//#define mp(x,y) make_pair(x,y)
int t,n,m;
struct node{
int v,w,nxt;
node(int v,int w,int nxt):v(v),w(w),nxt(nxt){};
node(){};
};
node ed[maxm*2];
int head[maxn],tot;
bool vis[maxn];
void addedge(int u,int v,int w)
{
ed[++tot].v=v;ed[tot].w=w;ed[tot].nxt=head[u];head[u]=tot;
}
ll dis[maxn][2];
queue<int>q;
vector<int>v;
int main()
{
scanf("%d",&t);
int kase=0;
while(t--){
v.clear();
tot=0;
memset(head,0,sizeof(head));
memset(vis,0,sizeof(vis));
scanf("%d%d",&n,&m);
for(int i=1,x,y,z;i<=m;i++){
scanf("%d%d",&x,&y);
for(int j=1;j<=y;j++){
scanf("%d",&z);
addedge(n+i,z,x);
addedge(z,n+i,0);
//addedge(n+1,z,x);
//addedge(z,n+1,x);
}
}
for(int i=0;i<maxn;i++){
dis[i][0]=dis[i][1]=1e18;
}
dis[1][0]=0;
q.push(1);
vis[1]=1;
while(!q.empty()){
int u=q.front();q.pop();vis[u]=0;
for(int i=head[u];i;i=ed[i].nxt){
node now=ed[i];
int v=now.v;
int w=now.w;
if(dis[v][0]>dis[u][0]+1ll*w){
dis[v][0]=dis[u][0]+1ll*w;
if(vis[v]==0){
vis[v]=1;
q.push(v);
}
}
}
}
memset(vis,0,sizeof(vis));
dis[n][1]=0;
q.push(n);
vis[n]=1;
while(!q.empty()){
int u=q.front();q.pop();vis[u]=0;
for(int i=head[u];i;i=ed[i].nxt){
node now=ed[i];
int v=now.v;
int w=now.w;
if(dis[v][1]>dis[u][1]+1ll*w){
dis[v][1]=dis[u][1]+1ll*w;
if(vis[v]==0){
vis[v]=1;
q.push(v);
}
}
}
}
ll ans=1e18;
for(int i=1;i<=n;i++){
if(ans>max(dis[i][0],dis[i][1])){
ans=max(dis[i][0],dis[i][1]);
}
//printf("%d ",dis[i][0]);
}
//printf("\n");
for(int i=1;i<=n;i++){
//printf("%d ",dis[i][1]);
if(ans==max(dis[i][0],dis[i][1]))v.push_back(i);
}
//printf("\n");
if(ans==1e18){
printf("Case #%d: Evil John\n",++kase);
continue;
}
printf("Case #%d: %lld\n",++kase,ans);
int k=v.size()-1;
for(int i=0;i<=k;i++){
printf("%d%c",v[i],i==k?'\n':' ');
}
}
return 0;
}