CF1790G Tokens on Graph - bfs -
题目链接:https://codeforces.com/contest/1790/problem/G
题解:
首先一个硬币如果能移动到根节点,必然从他的父亲开始一直到根的路径都是bonus
考虑钦定让某个硬币移动到根,其它的硬币能否为其提供足够的步数。因为是个图,所以先用 bfs 求一下根到这个点的 路径全为 bonus 的最短路径(或者是这个点邻居的最短路径+1)
如何判断能否提供足够步数呢?首先如果 \(i\) 点和 \(i\) 点相邻的一个点都是 bonus,那么 \(j, (j,i) \in E\) 点上的硬币一定可以贡献无数次步数
否则,如果 \(i\) 点是 bonus且没有邻居是 bonus,那么 \(j, (j,i) \in E\) 只能贡献一次步数,注意贡献步数的点和这个点是不是 bonus没有关系,和邻居有关
最后判断的时候就看一下除了这个点之外是否存在 \(i\) 为无限贡献,或者只能贡献1次的 \(i\) 的个数 \(\geq\) dis-1 (因为可以一开始先让钦定的硬币移动)
\(type[i]=2\) 代表 \(i,j\) 都是bonus,\(ntype[i]=2\) 代表 \(i\) 的某个邻居是\(type=2\) ,因此 \(i\) 能贡献无数次步数
// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define pii pair<int,int>
using namespace std;
typedef long long ll;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 2e5+5;
int n,m,p,b,dis[maxn], bonus[maxn], type[maxn], ntype[maxn];
vector<int>g[maxn];
void solve(){
scanf("%d%d",&n,&m);
scanf("%d%d",&p,&b);
for(int i=1;i<=n;i++)dis[i] = -1, g[i].clear(), bonus[i] = type[i] = ntype[i] = 0;
vector<int>token;
int win = 0;
for(int i=1;i<=p;i++){
int x;scanf("%d",&x);
token.push_back(x);
if(x == 1)win = 1;
}
for(int i=1;i<=b;i++){
int x;scanf("%d",&x);
bonus[x] = 1;
}
for(int i=1;i<=m;i++){
int x,y;scanf("%d%d",&x,&y);
g[x].push_back(y), g[y].push_back(x);
}
for(int i=1;i<=n;i++){
for(int v : g[i]){
if(bonus[i] && bonus[v]){
type[i] = 2;
}
}
}
for(int i : token){
for(int j : g[i]){
if(bonus[j])ntype[i] = 1;
if(type[j] == 2){
ntype[i] = 2;
break;
}
}
}
queue<int>Q;
Q.push(1);dis[1] = 0;
while(!Q.empty()){
int u = Q.front();Q.pop();
for(int v : g[u]){
if(bonus[v] && (dis[v] == -1)){
dis[v] = dis[u] + 1;
Q.push(v);
}
}
}
int cnt[4];memset(cnt,0,sizeof cnt);
for(int i=1;i<=n;i++)++ cnt[ntype[i]];
for(int i : token){
-- cnt[ntype[i]];
int res = ~dis[i] ? dis[i] : INF;
for(int u : g[i]){
if(~dis[u]){
res = min(res, dis[u] + 1);
}
}
if(res != INF){
if(cnt[2] >= 1 || cnt[1] >= (res-1)){
puts("YES");
return ;
}
}
++ cnt[ntype[i]];
}
puts(win ? "YES" : "NO");
}
signed main(){
// freopen("G.in","r",stdin);
int te;scanf("%d",&te);
while(te--)solve();
return 0;
}