Meeting(分层图+最短路径)
Meeting
题目链接:Meeting
考点:最短路+分层图
题意:
给若干个集合,集合内的节点之间的距离是t
问从1到n 双向奔赴的最短距离。
思路比较好想:直接用 1 和 n 为起点跑两遍dijstrra。
难点是建图。每个集合节点互相连边的话要n^2 条边
每一个集合都建立一个虚拟原点,连接这一集合的所有的点。
再跑dj就可以了
代码部分:
#include<bits/stdc++.h>
#include <stdio.h>
#include<numeric>
#include<iostream>
#include<string.h>
#include<string>
#include<algorithm>
#include<math.h>
#include <vector>
#include<stack>
#include<list>
#include<set>
#include<ctime>
#include<queue>
#include<utility>
#include<map>
#include<stdlib.h>
#define deg(a) cout<<#a<<'='<<a<<"\n"
#define lowbit(x) ((x)&(-x))
#define pll pair<int,int>
#define int long long
#define endl '\n'
using namespace std;
using i64 = long long;
const int N = 2e6+1000;
const int mod1 =998244353;
const int mod2 =1e9+7;
const int INF =0x3f3f3f3f3f3f3f;
std::vector<pll> G[N];
int dis1[N]={0};
int dis2[N]={0};
void dijkstra(int s, int *dis)//s表示起点 dis是距离数组
{
bool vis[N];// 标记
priority_queue<pll> ss;
memset(vis, 0, sizeof(vis));
dis[s] = 0;
ss.push(make_pair(0, s));
while(!ss.empty())
{
int u = ss.top().second;
int sum = ss.top().first;
ss.pop();
if(vis[u])
continue;
vis[u] = 1;
for(int i = 0; i < G[u].size(); i++)
{
int v = G[u][i].first;
if(dis[v] > dis[u] + G[u][i].second)
{
dis[v] = dis[u] + G[u][i].second;
ss.push(make_pair(-dis[v], v));
}
}
}
}
void solve(int case1)
{
int n,m;
cin>>n>>m;
int p=n+m; int cnt=0;
memset(dis1,INF,sizeof dis1);
memset(dis2,INF,sizeof dis2);
for(int i=1;i<=1e6+1000;i++)
{
G[i].clear();
}
dis1[1]=0;
dis2[n]=0;
for(int i=1;i<=m;i++)
{
int x,y;//x为边权,y为数量
cin>>x>>y;
for(int j=1;j<=y;j++)
{
int u;
cin>>u;
G[u].push_back({p+cnt,0});//点到虚拟原点的路径为0
G[p+cnt].push_back({u,x});//反过来为x
// G[p+cnt+1].push_back({p+cnt,x});
// G[p+cnt].push_back({p+cnt+1,x});
}
cnt+=1;
}
dijkstra(1,dis1);
dijkstra(n,dis2);
// for(int i=1;i<=n;i++) cout<<dis1[i]<<" ";
// cout<<endl;
// for(int i=1;i<=n;i++) cout<<dis2[i]<<" ";
// cout<<endl;
int anss=1e18;
for(int i=1;i<=n;i++)
{
if(dis1[i]>=1e18||dis2[i]>=1e18) continue;
int x=max(dis1[i],dis2[i]);
anss=min(anss,x);// cout<<anss<<" ";deg(x);
}
if(anss==1e18){
cout<<"Case #"<<case1<<": Evil John"<<endl;
return;
}
cout<<"Case #"<<case1<<": "<<anss<<endl;
for(int i=1;i<=n;i++)
{
if(dis1[i]>=1e18||dis2[i]>=1e18) continue;
int x=max(dis1[i],dis2[i]);
if(x==anss) cout<<i<<' ';
}
cout<<endl;
}
signed main()
{
cin.tie(nullptr);
ios::sync_with_stdio(false);
int kk = 1;
cin >> kk;
// cin.get();
// while(kk--) solve(kk);
for(int i=1;i<=kk;i++) solve(i);
return 0;
}

浙公网安备 33010602011771号