qdu校内排位赛-C-刚才有个朋友问我-( 对抗搜索 )

题目描述:

在这里插入图片描述

思路

对抗搜索
一、适用范围

在博弈论题目中,如果决策双方的获胜条件是截然相反的(即一方要求得分越高越好,另一方要求得分越低越好),这时我们就可以用上对抗搜索算法。

二、主要思路

dfs遍历博弈树。但是如果博弈树非常庞大,在不加优化的情况下,对抗搜索的时间效率十分低下,所以对抗搜索进行一定的优化。

三、主要优化

记忆化 和 Alpha−Beta剪枝 。
这里用的是记忆化(因为记忆化简单/(ㄒoㄒ)/~~)

再看这个题,经典对抗搜索,怎么记忆化呢??( 看看题目,n,m<=500 , s<=50 , 这不记忆化就来了。。。)
f [ x ] [ y ] [ s ] 记录当前位于 x , y , 且钱数是 s 的状态(记录当前的状态),下一次再访问到时直接将记录下来的结果返回即可。

同时自己的回合跟表弟的回合都可能遍历两种或者四种状态:

如果此点不是商店,那么就是 当前钱数+向下 、当前钱数+向右 两种状态;

如果此点是商店,那么就是 当前钱数+向下,当前钱数+向右 或者 0 + 向下、0 + 向右 四种状态( 当前钱数变为0,是因为换取水晶钱都没了。。。)

剩下的就是常规搜了,没啥坑点了(哦,还有,会爆int , 开long long)

代码
#include<iostream>
#include<string>
#include<map>
#include<set>
//#include<unordered_map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<fstream>
#define X first 
#define Y second
#define INF 0x3f3f3f3f
#define pii pair<int, int>
//#define pdi pair<double,int>
//#define int long long 
using namespace std;
typedef long long ll;
typedef unsigned long long llu; 
const int maxn=1e6+10;
int n,m,w,a[510][510];
ll f[510][510][60];
bool vis[510][510];
struct node
{
	int s;
	int d;
}p[510][510];
bool check(int x,int y)
{
	if(x>n||y>m) return 0;
	else return 1;
}
ll dfs(int x,int y,int pos,int money)
{
	money=min(50,money);
	//因为 s 最多是 50 ,所以如果当前你所拥有的钱 >= 50 ,事实上就相当于你只拥有 50。 
	if(f[x][y][money]!=-1) return f[x][y][money];
	//记忆化,避免超时 
	if(x==n&&y==m) return 0;
	//如果到终点了,就返回 0 (因为终点不可能有商店,所以获得的水晶数目是 0 ) 
	ll ans,flag=0;
	if(pos)//表弟 
	{
		ans=1ll*INF*INF;
		if(vis[x][y])  
			if(money>=p[x][y].s)
				flag=1; //标记兑换了水晶 ,金钱要变为 0   
		if(check(x+1,y)&&flag) ans=min(ans,p[x][y].d+dfs(x+1,y,pos^1,0+a[x+1][y]));
		if(check(x,y+1)&&flag) ans=min(ans,p[x][y].d+dfs(x,y+1,pos^1,0+a[x][y+1]));		
		if(check(x+1,y)) ans=min(ans,dfs(x+1,y,pos^1,money+a[x+1][y]));
		if(check(x,y+1)) ans=min(ans,dfs(x,y+1,pos^1,money+a[x][y+1]));
	}
	else//我 
	{
		ans=-1ll*INF*INF;
		if(vis[x][y]) 
			if(money>=p[x][y].s)
				flag=1; //标记兑换了水晶 ,金钱要变为 0  
		if(check(x+1,y)&&flag) ans=max(ans,p[x][y].d+dfs(x+1,y,pos^1,0+a[x+1][y]));
		if(check(x,y+1)&&flag) ans=max(ans,p[x][y].d+dfs(x,y+1,pos^1,0+a[x][y+1]));
		if(check(x+1,y)) ans=max(ans,dfs(x+1,y,pos^1,money+a[x+1][y]));
		if(check(x,y+1)) ans=max(ans,dfs(x,y+1,pos^1,money+a[x][y+1]));
	}
	return f[x][y][money]=ans;
}
int main( )
{
//	ios::sync_with_stdio(false);
	memset(f,-1,sizeof(f));
	//不赋值为 0 的原因是,如果一个商店也没有的话,那么记忆化的 f 数组也是0,跟没搜之前一样,那就成爆搜了,会 T
	//但事实上你可能已经搜过了,所以赋值为 -1 ,就可以避免这样的事情发生。 
    scanf("%d%d%d",&n,&m,&w);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		    scanf("%d",&a[i][j]);
	for(int i=1;i<=w;i++)
	{
		int x,y,s,d;
		scanf("%d%d%d%d",&x,&y,&s,&d);
		p[x][y].s=s;
		p[x][y].d=d;
		vis[x][y]=1;
	}
	printf("%lld",dfs(1,1,0,a[1][1]));
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值