这道题是 α−β\alpha - \beta 剪枝。

首先,你需要了解什么是 α−β\alpha - \beta 剪枝。

图片直接扒 OIWIKI 的了。

不保证本人理解正确无误。

Minimax

首先引入是一个叫 Minimax 算法的东西。

现在在一个树的顶端,先手需要让答案更大,而后手需要让答案更小,每一次一个人可以选择一颗子树向下移动。

这一个问题可以直接在树上每一个节点找出这个节点的答案,然后根节点就是最后的答案。

图中方框节店会选择最大的子节点移动,而圆形节点会选择最小的节点向后移动,于是就建出了树。

Alpha–Beta 剪枝

刚刚的方法很好,但是当数据范围很大的时候,这个树可能就建不出来了,所以有一个剪枝:Alpha–Beta 剪枝。

看一下大概的思路:

我们每一次走到一个节点,会向下遍历,然后此时,我们就需要记录一些信息。

我们记录下 α\alpha 和 β\beta,表示最小能够获得的和最大能够获得的答案。

比如这张图中,下面的 A 节点,遍历过 33 之后发现 33 很小,所以答案不可能大于 33 了,将 β\beta 设置成 33。

那这样有什么用呢?

看这张图:

途中我们算出了 A 然后现在上传到 B,由于 A 的 β\beta 为 33,所以 B 的答案不小于 33,将 B 的 α\alpha 设置成 33。

然后此时我们再来算 C 节点,要想对 B 有贡献,至少要提供 33,然后我们访问 C 中大小为 22 的节点,发现最大能提供的只有 22,了,所以矛盾,C 的其他节点不用访问了。

通过这种操作,我们就可以省去很多不必要的搜索。

好像也不是很难?

此题思路

这道题中,我们就设计答案为 −1-1 和 11,先手需要让答案变成 11。操作就是向里面循环枚举每一个空的点位填数,然后来模拟遍历上面讲的树。

代码

轻微压行,还是可读。

C++
#include<bits/stdc++.h>
using namespace std;
struct node{
	int x,y;
};
char c[4][4];
string s,q[110];
int tot=0;
bool check(char c[4][4],char p){
	for(int i=0;i<4;i++){
		if(c[i][0]==p&&c[i][1]==p&&c[i][2]==p&&c[i][3]==p)return 1;
		if(c[0][i]==p&&c[1][i]==p&&c[2][i]==p&&c[3][i]==p)return 1;
	}
	if(c[0][0]==p&&c[1][1]==p&&c[2][2]==p&&c[3][3]==p)return 1;
	if(c[0][3]==p&&c[1][2]==p&&c[2][1]==p&&c[3][0]==p)return 1;
	return 0;
}
bool full(char c[4][4]){
	for(int i=0;i<4;i++)for(int j=0;j<4;j++)if(c[i][j]=='.')return 0;
	return 1;
}
int ab(char c[4][4],int a,int b,bool m){
	if(check(c,'x'))return 1;
	if(check(c,'o'))return -1;
	if(full(c))return 0;
	int mn=1e9,mx=-1e9;
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++)if(c[i][j]=='.'){
			char t[4][4];
			for(int x=0;x<4;x++)for(int y=0;y<4;y++)t[x][y]=c[x][y];
			if(m)t[i][j]='x';
			else t[i][j]='o';
			int go=ab(t,a,b,m^1);
			if(m){
				mx=max(mx,go);
				a=max(a,go);
			}else{
				mn=min(mn,go);
				b=min(b,go);
			}
			if(b<=a)break;
		}
		if(b<=a)break;
	}
	return (m?mx:mn);
}
node solve(char c[4][4]){
	for(int i=0;i<4;i++)for(int j=0;j<4;j++)if(c[i][j]=='.'){
		char t[4][4];
		for(int x=0;x<4;x++)for(int y=0;y<4;y++)t[x][y]=c[x][y];
		t[i][j]='x';
		if(check(t,'x'))return {i,j};
		if(ab(t,-1e9,1e9,0))return {i,j};
	}
	return {-1,-1};
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	string s;
	while(getline(cin,s)&&s[0]!='$'){
		while(s[0]==0)getline(cin,s);
		if(s[0]=='$')break;
		for(int i=0;i<4;i++)for(int j=0;j<4;j++){
			cin>>c[i][j];
		}
		node ans=solve(c);
		if(ans.x==-1)cout<<"#####\n";
		else cout<<"("<<ans.x<<","<<ans.y<<")"<<'\n';
	}
	return 0;
}