• bzoj5248: [2018多省省队联测]一双木棋


    Description

    菲菲和牛牛在一块n行m列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手。棋局开始时,棋盘上没有任何棋子,

    两人轮流在格子上落子,直到填满棋盘时结束。落子的规则是:一个格子可以落子当且仅当这个格子内没有棋子且

    这个格子的左侧及上方的所有格子内都有棋子。

    棋盘的每个格子上,都写有两个非负整数,从上到下第i行中从左到右第j列的格子上的两个整数记作Aij、Bij。在

    游戏结束后,菲菲和牛牛会分别计算自己的得分:菲菲的得分是所有有黑棋的格子上的Aij之和,牛牛的得分是所

    有有白棋的格子上的Bij的和。

    菲菲和牛牛都希望,自己的得分减去对方的得分得到的结果最大。现在他们想知道,在给定的棋盘上,如果双方都

    采用最优策略且知道对方会采用最优策略,那么,最终的结果如何

    Input

    第一行包含两个正整数n,m,保证n,m≤10。

    接下来n行,每行m个非负整数,按从上到下从左到右的顺序描述每个格子上的

    第一个非负整数:其中第i行中第j个数表示Aij。

    接下来n行,每行m个非负整数,按从上到下从左到右的顺序描述每个格子上的

    第二个非负整数:其中第i行中第j个数表示Bij

    n, m ≤ 10 , Aij, Bij ≤ 100000

    Output

    输出一个整数,表示菲菲的得分减去牛牛的得分的结果。

    Sample Input

    2 3
    2 7 3
    9 1 2
    3 7 2
    2 3 1
    

    Sample Output

    2
    

    题解1

    直接对抗搜索可以得50分

    题解2

    对抗搜索+Alpha-Beta剪枝可以得70分

    题解3

    对抗搜索+记忆化可以得100分

    就是开一个map存一下每个状态的值,如果访问过这个状态直接返回即可。

    由于任意时刻棋盘上的棋子一定是四连通且聚集在左上角,中间不会有空洞,因此就可以把状态按照每行的个数压成一个M进制数。枚举下棋的位置时也不用所有的位置都枚举,只用枚举下到哪一行即可。

    代码1 (50pts)

    #include<bits/stdc++.h>
    #define MAXN 22
    #define INF 0x7fffffff
    #define LL long long
    namespace IO{
    	char buf[1<<15],*fs,*ft;
    	inline char gc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
    	inline int qr(){
    		int x=0,rev=0,ch=gc();
    		while(ch<'0'||ch>'9'){if(ch=='-')rev=1;ch=gc();}
    		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=gc();}
    		return rev?-x:x;}
    }using namespace IO;
    using namespace std;
    int num[MAXN],N,M,a[MAXN][MAXN],b[MAXN][MAXN];
    int Alpha_Beta(int now,int alpha,int beta){
    	if(now==N*M)return 0;
    	if(!(now&1)){//先手 
    		alpha=-INF;
    		if(num[1]<M){
    			num[1]++;
    			alpha=max(alpha,Alpha_Beta(now+1,alpha,beta)+a[1][num[1]]);
    			num[1]--;
    		}
    		for(int i=2;i<=N;i++){
    			if(num[i]>=num[i-1])continue;
    			num[i]++;
    			alpha=max(alpha,Alpha_Beta(now+1,alpha,beta)+a[i][num[i]]);
    			num[i]--;
    		}
    		return alpha;
    	}
    	else{//后手 
    		beta=INF;
    		if(num[1]<M){
    			num[1]++;
    			beta=min(beta,Alpha_Beta(now+1,alpha,beta)-b[1][num[1]]);
    			num[1]--;
    		}
    		for(int i=2;i<=N;i++){
    			if(num[i]>=num[i-1])continue;
    			num[i]++;
    			beta=min(beta,Alpha_Beta(now+1,alpha,beta)-b[i][num[i]]);
    			num[i]--;
    		}
    		return beta;
    	}
    }
    int main(){
    	#ifndef ONLINE_JUDGE
    	freopen("chess.in","r",stdin);
    	freopen("chess.out","w",stdout);
    	#endif
    	N=qr();M=qr();
    	for(int i=1;i<=N;i++){
    		for(int j=1;j<=M;j++){
    			a[i][j]=qr(); 
    		}
    	}
    	for(int i=1;i<=N;i++){
    		for(int j=1;j<=M;j++){
    			b[i][j]=qr(); 
    		}
    	}
    	printf("%d",Alpha_Beta(0,-INF,INF));
    	return 0;
    }
    

    代码2 (70pts)

    #include<bits/stdc++.h>
    #define MAXN 22
    #define INF 0x7fffffff
    #define LL long long
    namespace IO{
    	char buf[1<<15],*fs,*ft;
    	inline char gc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
    	inline int qr(){
    		int x=0,rev=0,ch=gc();
    		while(ch<'0'||ch>'9'){if(ch=='-')rev=1;ch=gc();}
    		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=gc();}
    		return rev?-x:x;}
    }using namespace IO;
    using namespace std;
    int num[MAXN],N,M,a[MAXN][MAXN],b[MAXN][MAXN];
    int Alpha_Beta(int now,int alpha,int beta,int nowa,int nowb){
    	if(now==N*M)return nowa-nowb;
    	if(!(now&1)){//先手 
    		if(num[1]<M){
    			num[1]++;
    			alpha=max(alpha,Alpha_Beta(now+1,alpha,beta,nowa+a[1][num[1]],nowb));
    			num[1]--;
    			if(alpha>=beta)return alpha;
    		}
    		for(int i=2;i<=N;i++){
    			if(num[i]>=num[i-1])continue;
    			num[i]++;
    			alpha=max(alpha,Alpha_Beta(now+1,alpha,beta,nowa+a[i][num[i]],nowb));
    			num[i]--;
    			if(alpha>=beta)return alpha;
    		}
    		return alpha;
    	}
    	else{//后手 
    		if(num[1]<M){
    			num[1]++;
    			beta=min(beta,Alpha_Beta(now+1,alpha,beta,nowa,nowb+b[1][num[1]]));
    			num[1]--;
    			if(alpha>=beta)return beta;
    		}
    		for(int i=2;i<=N;i++){
    			if(num[i]>=num[i-1])continue;
    			num[i]++;
    			beta=min(beta,Alpha_Beta(now+1,alpha,beta,nowa,nowb+b[i][num[i]]));
    			num[i]--;
    			if(alpha>=beta)return beta;
    		}
    		return beta;
    	}
    }
    int main(){
    	#ifndef ONLINE_JUDGE
    	freopen("chess.in","r",stdin);
    	freopen("chess.out","w",stdout);
    	#endif
    	N=qr();M=qr();
    	for(int i=1;i<=N;i++){
    		for(int j=1;j<=M;j++){
    			a[i][j]=qr(); 
    		}
    	}
    	for(int i=1;i<=N;i++){
    		for(int j=1;j<=M;j++){
    			b[i][j]=qr(); 
    		}
    	}
    	printf("%d",Alpha_Beta(0,-INF,INF,0,0));
    	return 0;
    }
    

    代码3 (AC)

    #include<bits/stdc++.h>
    #define MAXN 22
    #define INF 0x7fffffff
    #define LL long long
    namespace IO{
    	char buf[1<<15],*fs,*ft;
    	inline char gc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
    	inline int qr(){
    		int x=0,rev=0,ch=gc();
    		while(ch<'0'||ch>'9'){if(ch=='-')rev=1;ch=gc();}
    		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=gc();}
    		return rev?-x:x;}
    }using namespace IO;
    using namespace std;
    map<LL,int> mp;
    int num[MAXN],N,M,a[MAXN][MAXN],b[MAXN][MAXN];
    inline LL Hash(){
    	LL ret=0;
    	for(int i=1;i<=N;i++)ret=ret*(M+1)+num[i];
    	return ret;
    }
    int DFS(int now){
    	LL tmp=Hash();
    	if(mp.find(tmp)!=mp.end())return mp[tmp];
    	if(now==N*M)return 0;
    	int val;
    	if(!(now&1)){//先手 
    		val=-INF;
    		if(num[1]<M){
    			num[1]++;
    			val=max(val,DFS(now+1)+a[1][num[1]]);
    			num[1]--;
    		}
    		for(int i=2;i<=N;i++){
    			if(num[i]>=num[i-1])continue;
    			num[i]++;
    			val=max(val,DFS(now+1)+a[i][num[i]]);
    			num[i]--;
    		}
    		mp[tmp]=val;
    	}
    	else{//后手 
    		val=INF;
    		if(num[1]<M){
    			num[1]++;
    			val=min(val,DFS(now+1)-b[1][num[1]]);
    			num[1]--;
    		}
    		for(int i=2;i<=N;i++){
    			if(num[i]>=num[i-1])continue;
    			num[i]++;
    			val=min(val,DFS(now+1)-b[i][num[i]]);
    			num[i]--;
    		}
    		mp[tmp]=val;
    	}
    	return mp[tmp];
    }
    int main(){
    	#ifndef ONLINE_JUDGE
    	freopen("chess.in","r",stdin);
    	freopen("chess.out","w",stdout);
    	#endif
    	N=qr();M=qr();
    	for(int i=1;i<=N;i++){
    		for(int j=1;j<=M;j++){
    			a[i][j]=qr(); 
    		}
    	}
    	for(int i=1;i<=N;i++){
    		for(int j=1;j<=M;j++){
    			b[i][j]=qr(); 
    		}
    	}
    	printf("%d",DFS(0));
    	return 0;
    }
    
  • 相关阅读:
    Android对话框自定义标题
    JSONObject和JSONArray的关系
    Java的List排序
    重写onStart()函数
    SSH框架执行自己定义的SQL语句
    nested exception is org.hibernate.QueryException: could not resolve property
    java.lang.NullPointerException org.apache.struts2.impl.StrutsActionProxy.getErrorMessage(StrutsActionProxy.java:69)
    Java项目打包部署war文件
    一道腾讯面试题
    SSH服务器与Android通信(3)--Android客户端发送数据
  • 原文地址:https://www.cnblogs.com/lrj998244353/p/8763289.html
Copyright © 2020-2023  润新知