原题链接
题目大意
香浓切换游戏的变体规则如下:
给定有重边的无向图
G
=
(
V
,
E
)
G=(V,E)
G=(V,E), 和两个点
s
,
t
∈
V
s,t \in V
s,t∈V。 最初在
s
s
s 点上有一个令牌。两个玩家
J
o
i
n
P
l
a
y
e
r
Join\ Player
Join Player 和
C
u
t
P
l
a
y
e
r
Cut\ Player
Cut Player 轮流进行以下操作,Cut Player先手:
- 如果轮到Join Player,如果令牌在点 u u u ,则选择边 ( u , v ) ∈ E (u,v) \in E (u,v)∈E,删除它并将令牌移动到点 v v v。
- 如果轮到Cut Player,如果令牌在点
u
u
u ,则选择边
(
u
,
v
)
∈
E
(u,v) \in E
(u,v)∈E,删除它。
当任意玩家无法进行操作时,游戏结束。
如果令牌在游戏期间到达点 t t t ,则Join Player获胜。反之Cut Player获胜。
假设双方均采取最优策略,给定图 G G G ,求谁回获胜。
题解
考虑,若当前只有一条路可以走向终点,那么Cut Player 就可以删去这一条路获得胜利。
而当前选择
>
1
>1
>1 可以走向终点时,Cut Player只能删去一条,还可以继续走。
那么答案就很明晰了,选择一条路,若其中的每一个节点都有超过一种方案能到达终点,则Join Player获胜,反之Cut Player获胜。
由于在图上进行操作,我们考虑倒着枚举,从终点开始遍历,如果从终点可以到达一个节点两次即以上则它可以继续向前,表明该点是可以到达终点的,如果能到达起点,则存在上面说明的路径。
注意:终点不可以通过多次,否则会死循环。
参考代码
#include<bits/stdc++.h>
using namespace std;
const int N=105;
vector<int> v[N];
int b[N];
int n,m,s,t,T;
void dfs(int x)
{
b[x]++;
if(b[x]!=2) //若小于2,则无法通过,若大于2,则已经通过
return;
for(int i=0;i<v[x].size();i++)
dfs(v[x][i]);
}
int main()
{
// freopen("1.txt","r",stdin);
// freopen("2.txt","w",stdout);
cin>>T;
while(T--)
{
scanf("%d%d%d%d",&n,&m,&s,&t);
for(int i=1;i<=n;i++)
v[i].clear(),b[i]=0;
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
b[t]=1; //终点不允许通过多次
dfs(t);
// for(int i=1;i<=n;i++)
// cout<<dp[i]<<endl;
if(b[s]>=2) //存在路径
puts("Join Player");
else
puts("Cut Player");
}
}