[ABC302F] Merge Set 题解
Augen_stern · · 题解
Part 1: 分析求解
套路建图题,读完题不难可以构造出一个二分图,左边是每个集合,称为集合点,右边是
而题目要求的是一个集合包含
一次操作中使用的两个集合相当于从第一个集合点到其中的一个数字点再到第二个集合点,代价为
所以我们只需要将每一个集合点连向相匹配的数字点,代价为
Part 2: CODE
//#pragma GCC optimize(3)
#include<iostream>
#include<climits>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<assert.h>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
//#include<random>
//#include<chrono>
#define int long long
//#define double long double
using namespace std;
const long long INF=LLONG_MAX/2ll;
const long long mod=998244353;
//const long long mod=1000000007;
const double Pai=acos(-1);
const double eps=1e-8;
int n,m,cnt=0;
int dis[1000005],h[1000005],vst[1000005];
struct edge {
int to,next,v;
}e[1000005];
void addedge(int x,int y,int z) {
cnt++;
e[cnt].to=y;
e[cnt].v=z;
e[cnt].next=h[x];
h[x]=cnt;
}
priority_queue< pair<int,int> > q;
void Dij(int s) {
for(int i=1;i<=n+m;i++) dis[i]=INF,vst[i]=0;
dis[s]=0,q.push({-dis[s],s});
while(!q.empty()) {
int u=q.top().second;q.pop();
if(vst[u]) continue;
vst[u]=1;
for(int i=h[u];i;i=e[i].next) {
int y=e[i].to;
if(dis[y]>dis[u]+e[i].v) {
dis[y]=dis[u]+e[i].v;
q.push({-dis[y],y});
}
}
}
}
signed main() {
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) {
int x;scanf("%lld",&x);
for(int j=1;j<=x;j++) {
int y;scanf("%lld",&y);
addedge(i+m,y,0),addedge(y,i+m,1);
}
}
Dij(1);
if(dis[m]==INF) puts("-1");
else printf("%lld",dis[m]-1);
return 0;
}