传送门:Connect3
初解此题就感觉是模拟,但算了算最暴力的时间复杂度:每次有4种可能的位置,最大走16次,则最大运算4^16
显然爆炸。
这样像显然有点bug,先不考虑黑白交替,就单单考虑每个格子的可能颜色,最大也只有2^16
。所以4^16
明显是错误错误。
再考虑到每过一次都要进行颜色交换,最大的预算为C(16,32)
(这还是没有考虑不可行解)
如果再过程种剪枝,时间复杂度完全在可行范围内。
但是怎么存储状态呢?
位标记!关于位标记我之前研究过,但做题的时候没有想起来,很遗憾。
综上:此题是模拟+剪枝+位标记。
知道思路了之后就是写代码的时间了,模拟题很考验一个选手的码力如何,今天尝试写了一发,然后明白了:蒟蒻只配写hello world!
。所以以后这种题还是交个队友吧!(狗头保命)
AC代码如下:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int f1[10]={0,-1,1,0,0,1,-1,1,-1};
int f2[10]={0,1,-1,1,-1,1,-1,0,0};
int a,b,ans=0;
int h[10],s[10][10];
map<ll,int>m;
ll find_it()
{
ll state=0;
for(int i=1;i<=4;i++)
{
for(int j=1;j<=4;j++)
{
state=(state<<2)+s[i][j];
}
}
return state;
}
bool iswin(int p)
{
for(int i=1;i<=4;i++)
{
for(int j=1;j<=4;j++)
{
for(int k=1;k<=8;k+=2)
{
int x1=i+f1[k],y1=j+f2[k];
int x2=i+f1[k+1],y2=j+f2[k+1];
if(x1<1||x1>4||y1<1||y1>4||x2<1||x2>4||y2<1||y2>4)continue;
else
{
if(s[x1][y1]==s[x2][y2]&&s[x1][y1]==s[i][j]&&s[i][j]==p)return 1;
}
}
}
}
return 0;
}
void solve(int now)
{
ll state=find_it();
if(m[state])return;
m[state]=1;
if(iswin(1) || iswin(2) || s[b][a])
{
if(iswin(2) && s[b][a] == 2)
{
ans++;
return;
}
return;
}
for(int i=1;i<=4;i++)
{
if(h[i]==4)continue;
h[i]++;
s[i][h[i]]=now;
if(now==1)solve(2);
else if(now==2)solve(1);
s[i][h[i]]=0;
h[i]--;
}
return;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t>>a>>b;
h[t]++;
s[t][1]=1;
solve(2);
cout<<ans<<endl;
return 0;
}
关于这个代码,自认为处理的较好的是iswin()
函数,使用了f1,f2
数组来减少码量。
但写跨的是这个判断。(下面是标答)
if(iswin(1) || iswin(2) || s[b][a])
{
if(iswin(2) && s[b][a] == 2)
{
ans++;
return;
}
return;
}
但我一开始写的是:(错误写法)
if(iswin(1))return ;
else if(iswin(2))
{
if(s[b][a]==2)
{
for(int k=1;k<=8;k+=2)
{
int x1=a+f1[k],y1=a+f2[k];
int x2=b+f1[k+1],y2=b+f2[k+1];
if(s[x1][y1]==s[x2][y2]&&s[x1][y1]==s[a][b]&&s[a][b]==2)
{
ans++;
break;
}
}
return;
}
else return ;
}