https://vjudge.net/problem/Gym-102501L
题意:
L题是个游戏,网格中,有连通(上下左右)的星,每块连通的星会接触左边界和右边界,大小至多2N。两块连通的星的任意两个点之间距离至少为3。
现在轮流放置照相机,需要接触星,接触同一块连通的星的照相机不能接触,x不能放置,问先手赢还是后手赢。
解析:
距离为3说明两个大块之间的game独立。一个大块上放照相机不能互相接触,说明可以将可以放照相机的’.'块通过连通性再次分割。
最后对于一个连通的’.‘块,由于保证一个大块最多只有20个点,所以’.'块感觉也差不多20个。
所以可以用状压dp跑SG函数,代码中的deal2函数处理的是这个。二进制中,1代表可以放,0代表已经被放置或与放置的相邻。答案的SG值为所有SG值的异或。SG不为0时先手赢。
代码:
/*
* Author : Jk_Chen
* Date : 2020-03-01-14.47.40
*/
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair<int, int>
#define fi first
#define se second
#define debug(x) cerr<<#x<<" = "<<x<<'\n'
const LL mod=1e9+7;
const int maxn=1e7+9;
const int inf=0x3f3f3f3f;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
#define rd rd()
/*_________________________________________________________begin*/
int n;
char x[13][13];
bool vis[13][13];
bool isw[13][13];
int di[4][2]={1,0,-1,0,0,1,0,-1};
void dfs(int a,int b){
vis[a][b]=1;
isw[a][b]=1;
rep(i,0,3){
int A=a+di[i][0],B=b+di[i][1];
if(A<1||A>n||B<1||B>n||x[A][B]!='*'||vis[A][B])continue;
dfs(A,B);
}
}
vector<pill>V;
int fa[109];
int fin(int p){return fa[p]==p?p:fa[p]=fin(fa[p]); }
int un(int a,int b){
int f1=fin(a),f2=fin(b);
if(f1!=f2)
fa[f1]=f2,fin(f1);
}
bool isNear(pill a,pill b){
rep(i,0,3){
pill tmp=a;
tmp.fi+=di[i][0],tmp.se+=di[i][1];
if(tmp.fi==b.fi&&tmp.se==b.se)return 1;
}
return 0;
}
vector<pill>VV;
int dp[maxn];
int deal2(){// 联通的'.'
int sta[109];
mmm(sta,0);
int n=VV.size();
rep(i,0,n-1){
sta[i]|=1<<i;
rep(j,0,n-1){
if(isNear(VV[i],VV[j])){
sta[i]|=1<<j;
}
}
}
dp[0]=0;
int MS=(1<<n)-1;
assert(MS+1<maxn);
rep(i,1,MS){
bool vis[30];
mmm(vis,0);
rep(j,0,n-1){
if(i&(1<<j)){
int To=i&(MS-sta[j]);
assert(To<i);
vis[dp[To]]=1;
assert(dp[To]+1<30);
}
}
for(int now=0;;now++){
if(!vis[now]){
dp[i]=now;break;
}
}
}
return dp[MS];
}
int deal(){// 与一块*联通的点
int n=V.size();
rep(i,0,n-1){
fa[i]=i;
}
rep(i,0,n-1){
rep(j,i+1,n-1){
if(isNear(V[i],V[j]))
un(i,j);
}
}
int SG=0;
rep(i,0,n-1){
VV.clear();
rep(j,0,n-1){
if(fin(j)==i)VV.pb(V[j]);
}
if(VV.size())
SG^=deal2();
}
return SG;
}
int main(){
n=rd;
rep(i,1,n){
scanf("%s",x[i]+1);
}
int SG=0;
rep(i,1,n)rep(j,1,n){
mmm(isw,0);
if(vis[i][j]||x[i][j]!='*')continue;
dfs(i,j);
V.clear();
rep(I,1,n)rep(J,1,n){// 空地
if(x[I][J]!='.')continue;
int is=0;
rep(_,0,3){
int II=I+di[_][0];
int JJ=J+di[_][1];
if(isw[II][JJ]){is=1;break;}
}
if(is)
V.pb({I,J});
}
if(V.size()){
SG^=deal();
}
}
if(SG!=0){
printf("First player will win\n");
}
else{
printf("Second player will win\n");
}
return 0;
}
/*_________________________________________________________end*/
来源:CSDN
作者:JK Chen
链接:https://blog.csdn.net/jk_chen_acmer/article/details/104595350