CF1790G Tokens on Graph - bfs -

题目链接:https://codeforces.com/contest/1790/problem/G

题解:
首先一个硬币如果能移动到根节点,必然从他的父亲开始一直到根的路径都是bonus
考虑钦定让某个硬币移动到根,其它的硬币能否为其提供足够的步数。因为是个图,所以先用 bfs 求一下根到这个点的 路径全为 bonus 的最短路径(或者是这个点邻居的最短路径+1)
如何判断能否提供足够步数呢?首先如果 i 点和 i 点相邻的一个点都是 bonus,那么 j,(j,i)E 点上的硬币一定可以贡献无数次步数
否则,如果 i 点是 bonus且没有邻居是 bonus,那么 j,(j,i)E 只能贡献一次步数,注意贡献步数的点和这个点是不是 bonus没有关系,和邻居有关
最后判断的时候就看一下除了这个点之外是否存在 i 为无限贡献,或者只能贡献1次的 i 的个数 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;
}
posted @   SkyRainWind  阅读(51)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示
点击右上角即可分享
微信分享提示