牛客多校-Shannon Switching Game-(博弈+递推必胜态)

60 篇文章 1 订阅

F

题意:
就是给你n个点m条边,然后给你一个初始点st,和一个好点ed。小A和小B轮流操作,小B先操作。如果现在在a点,那么小B可以让一条和a点相连的边删掉。如果现在在a点,那么小A可以选择一条边走过去,并且删去这条边。现在问你当两个人都没法操作的时候,小A是否可以经过好点ed。

思考:

  1. 刚开始看完,发现点的数量很小。然后画了画图发现,如果从a能走到b的话,要么a和b之间有两条边,要么可以从a走到好点,也就是小B必须删去这条边,所以我可以走a走到b。其实不然,下面这个图就卡死了。
    在这里插入图片描述这个图完全可以从st走到ed,但是我第一次像的就不可以。
  2. 但是这个想法就错了一点,就是一个点a可以走到b的话,要么a和b有两条边。要么a可以走到一个必胜点,必胜点就代表这个点可以经过好点ed。所以小B要砍断走向必胜点的,那么a就可以走到b了。但是我一想既然要预处理出来必胜点的话,我直接倒着推就好了,就是先从ed点往外边走,如果一个点可以有两条边走到必胜点,那么这个点也是必胜点。因为小B不管怎么删,我都可以走到必胜点。
  3. 当时我还有点困惑的是,比如在某个点的时候,为啥我就让小B先操作呢?因为既然你在某个点了,要么是初始点,要么是小A走过来的,所以正好该小B操作。还有就是想着会不会一个点入队多次呢?有环之类的,但是其实没有,因为进来的都是必胜点,既然是必胜点了,就肯定把别人更新了,如果再放一次就多更新别人了也。
  4. 所以这个题和之前做的都差不多,就是从已知的状态开始往前推,推着推着就把初始点的状态推出来了。牛客多校-Z-Game on grid

代码:

#include<bits/stdc++.h>
#define int long long
#define pb push_back
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);

using namespace std;

const int N = 110,M = 110;

int T,n,m;
int vis[N];
int flag[N];
int st,ed;

vector<int > e[N];

bool solve()
{
	queue<int > q;
	q.push(ed);
	vis[ed] = 2;
	while(q.size())
	{
		auto now = q.front();
		q.pop();
		if(flag[now]) continue;
		flag[now] = 1;
		for(auto spot:e[now])
		{
			if(vis[now]>=2) vis[spot]++;
		}
		for(auto spot:e[now])
		{
			if(vis[spot]>=2) q.push(spot);
		}
	}
	return vis[st]>=2;
}

signed main()
{
	IOS;
	cin>>T;
	while(T--)
	{
		cin>>n>>m>>st>>ed;
		for(int i=1;i<=n;i++)
		{
			e[i].clear();
			flag[i] = vis[i] = 0;
		}
		for(int i=1;i<=m;i++)
		{
			int a,b;
			cin>>a>>b;
			e[a].pb(b);
			e[b].pb(a);
		}
		solve()?cout<<"Join Player\n":cout<<"Cut Player\n";
	}
	return 0;
}

总结:
多多思考,多想想以前的模型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值