题意:
给你n个点和m组集合,让你求点1到点n的最短路。
这m组集合中,每行给一个t代表这个强连通集内任两点互相可达的时间,一个s表集合的容量,剩下s个数的是点的标号。
要输出的是一人在1,一人在n,是否存在中途某点,使二人最短时间相遇。
从两端各跑一遍dijkstra,分别记到dis1数组和disn数组中,
在i点实际相遇时间deed=max(dis1[i],disn[i]),再用一个ans去更新deed的最小值就好了。
题解:
我可能是计组没学好...这不就是直接相连变总线么...
建一个虚拟节点,使该节点与这个强连通集内每一节点连边,
向总线传输信息需要t,返回信息需要0(其实反过来也行,但想想似乎不符合超级节点定义)
这就实现了o(m*m)→o(m)的转化。
由于最后包含虚拟节点共有n+m个节点,相当于用1e6的n跑dijkstra。
思路来源:
https://blog.youkuaiyun.com/zcmartin2014214283/article/details/52748596
https://blog.youkuaiyun.com/yuanjunlai141/article/details/52713350
后记:
pli一个ll一个int的操作,以后还是写两个ll吧,真是太麻烦了。
手敲不出来堆优化dijkstra,感觉自己要被退学了。
Status | Accepted |
---|---|
Time | 2371ms |
Memory | 76100kB |
Length | 2538 |
Lang | C++ |
Submitted | 2018-09-20 23:53:07 |
Shared | |
RemoteRunId | 26340319 |
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <bitset>
#include <functional>
typedef long long ll;
const ll INF=9999999999999999;
const int mod=1e9+7;
const double eps=1e-7;
const int maxn=2000005;
#define vi vector<int>
#define si set<int>
#define pli pair<ll,int>
#define pi acos(-1.0)
#define pb push_back
#define mp make_pair
#define lowbit(x) (x&(-x))
#define sci(x) scanf("%d",&(x))
#define scll(x) scanf("%lld",&(x))
#define sclf(x) scanf("%lf",&(x))
#define pri(x) printf("%d",(x))
#define rep(i,j,k) for(int i=j;i<=k;++i)
#define per(i,j,k) for(int i=j;i>=k;--i)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
struct edge
{
int nex,to,w;
}e[maxn];
int head[maxn],cnt,tot,n,m,ans[maxn],num;
ll dis1[maxn],disn[maxn];//1节点跑一遍dijkstra,n节点跑一遍
priority_queue<pli,vector<pli>,greater<pli> >q;
bool vis[maxn];
void init(int n)
{
while(q.size())q.pop();
mem(head,-1);
mem(ans,0);
mem(e,0);
rep(i,0,maxn-1)
{
dis1[i]=INF;
disn[i]=INF;
}
num=0;//ans的个数
cnt=0;//边标号
tot=n;//虚拟节点初始标号
}
void add(int u,int v,int w)
{
e[cnt].to=v;
e[cnt].w=w;
e[cnt].nex=head[u];
head[u]=cnt++;
}
void dijkstra(ll dis[],int u)
{
while(q.size())q.pop();
mem(vis,0);
for(int i=head[u];~i;i=e[i].nex)
{
int v=e[i].to;
ll w=e[i].w;
dis[v]=w;
q.push(pli(dis[v],v));
}
dis[u]=0;vis[u]=1;
while(!q.empty())
{
pli tmp=q.top();
ll fir=tmp.first;
int sec=tmp.second;
q.pop();
if(vis[sec])continue;
vis[sec]=1;
for(int i=head[sec];~i;i=e[i].nex)
{
int v=e[i].to;
ll w=e[i].w;
if(dis[v]>dis[sec]+w)
{
dis[v]=dis[sec]+w;
q.push(pli(dis[v],v));
}
}
}
}
int main()
{
int t;
sci(t);
rep(k,1,t)
{
sci(n),sci(m);
init(n);
int t,s;
rep(i,0,m-1)
{
sci(t),sci(s);
rep(j,0,s-1)
{
int u;
sci(u);u--;
add(u,tot,t);
add(tot,u,0);
}
tot++;//虚拟节点
}
printf("Case #%d: ",k);
dijkstra(dis1,0);
if(dis1[n-1]==INF)
{
puts("Evil John");
continue;
}
dijkstra(disn,n-1);
ll res=INF;
rep(i,0,n-1)
{
ll deed=max(dis1[i],disn[i]);
res=min(res,deed);
}
printf("%lld\n",res);
rep(i,0,n-1)
{
ll tmp=max(dis1[i],disn[i]);
if(tmp==res)ans[num++]=i+1;
}
printf("%lld",ans[0]);
rep(i,1,num-1)printf(" %lld",ans[i]);
puts("");
}
return 0;
}