• 2020.11.24 考试题解


    搜索专题

    T1黑白棋游戏

    寻找最少步数,一看就知道是用广搜。 (虽然我考场上用的时深搜+迭代加深)
    每次只能与上下左右的交换,如果直接暴力枚举,肯定超时,考虑优化。

    <1> 如果有一个点和我们要交换的点颜色一样,就没必要换了。

    <2> 我们可以用状压,将每次的判断从(O(16))变为(O(1))

    有这些就可以了,要想更进一步,可以用双向搜索(不会,之后有空再补)。

    加强版的代码

    #include<bits/stdc++.h>
    using namespace std;
    #define il inline
    #define vocaloid(v) (v>='0'&&v<='9')
    template <typename T>
    il void read(T &x)
    {
    	x=0;char v=getchar();
    	while(!vocaloid(v)) v=getchar();
    	while(vocaloid(v)) {x=(x<<1)+(x<<3)+v-'0';v=getchar();}
    }
    int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
    int a[5][5],b[5][5],vis[(1<<16)-1],fa[(1<<16)-1];
    int res[100039][4];
    int Beg,End,IA;
    struct Ans{
    	int x,y,xx,yy,fa;
    }ans[100039];
    queue<int>q;
    il void init()//读入
    {
    	char c;
    	for(int i=1;i<=4;i++)
    		for(int j=1;j<=4;j++)
    		{
    			cin>>c;
    			a[i][j]=c-'0';
    		}
    	for(int i=1;i<=4;i++)
    		for(int j=1;j<=4;j++)
    		{
    			cin>>c;
    			b[i][j]=c-'0';
    		}
    }
    il int GetDeci(int x[5][5])//转成压缩的状态
    {
    	int comb=0,IA=0;
    	for(int i=4;i>=1;i--)
    		for(int j=4;j>=1;j--)
    		{
    			comb+=x[i][j]*pow(2,IA);
    			IA++;
    		}
    	return comb;
    }
    il void change(int x,int a[5][5])//根据状态转回棋盘
    {
    	while(x)
    	{
    		for(int i=4;i>=1;i--)
    			for(int j=4;j>=1;j--)
    			{
    				a[i][j]=x%2;
    				x/=2;
    			}
    	}
    }
    il bool check(int x,int y,int xx,int yy)
    {
    	if(xx<1||xx>4||yy<1||yy>4||a[x][y]==a[xx][yy]) return 0;
    	else return 1;
    }
    il void bfs()
    {
    	q.push(Beg);vis[Beg]=1;
    	while(!q.empty())
    	{
    		int x=q.front();q.pop();
    		change(x,a);
    		for(int i=1;i<=4;i++)
    			for(int j=1;j<=4;j++)
    			{
    				int x=i,y=j;
    				for(int k=0;k<=3;k++)
    				{
    					int xx=x+dx[k],yy=y+dy[k];
    					int flag=0;
    					if(check(x,y,xx,yy))
    					{
    						flag=1;
    						int now_Deci=GetDeci(a);
    						swap(a[x][y],a[xx][yy]);
    						int Deci=GetDeci(a);
    						if(!vis[Deci])
    						{
    							vis[Deci]=1;
    							ans[Deci]=(Ans){x,y,xx,yy,now_Deci};
    							fa[Deci]=now_Deci;
    							q.push(Deci);
    						}
    						if(Deci==End) return ;
    					}
    					if(flag)
    						swap(a[x][y],a[xx][yy]);
    				}
    			}
    	}
    }
    int main()
    {
    	freopen("game.in","r",stdin);
    	freopen("game.out","w",stdout);
    	init();
    	Beg=GetDeci(a),End=GetDeci(b);
    	bfs();
    	fa[Beg]=0;
    	while(fa[End])
    	{
    		IA++;
    		res[IA][0]=ans[End].x,res[IA][1]=ans[End].y,res[IA][2]=ans[End].xx,res[IA][3]=ans[End].yy;
    		End=fa[End];
    	}
    	printf("%d
    ",IA);
    	for(int i=IA;i>=1;i--)
    		printf("%d%d%d%d
    ",res[i][0],res[i][1],res[i][2],res[i][3]);
    	return 0;
    }
    

    T2乌龟棋

    对于这道题,我们可以打出一个非常暴力的暴力,时间复杂度大概为(O(m^m)),代码如下:

    il void dfs(int pos,int sum)
    {
    	if(pos==n) 
    	{
    		ans=max(ans,sum);
    		return ;
    	}
    	for(int i=1;i<=m;i++)
    	{
    		if(!vis[i])
    		{
    			vis[i]=1;
    			dfs(pos+card[i],sum+a[pos+card[i]]);
    			vis[i]=0;
    		}
    	}
    }
    

    肯定超时,所以我们需要优化。

    我们注意到题目中说只有(1,2,3,4)四种卡牌,且每张不超过(50)张。所以我们可以开一个四位数组(f_{i,j,p,q}),表示使用了(1)卡牌(i)张,(2)卡牌(j)张,(3)卡牌(p)张,(4)卡牌(q)张时获得的最大分数。

    我们不必关心这契卡牌是以怎样的顺序使用的,反正最后都会走到同一个位置,所以我们可以用记忆化搜索或动规,转移方程为:

    [f_{i,j,p,q}=max{(f_{i-1,j,p,q},f_{i,j-1,p,q},f_{i,j,p-1,q},f_{i,j,p,q-1})}+a_{now} ]

    [now=1+1 imes i+2 imes j+3 imes p+4 imes q ]

    接下来就可以直接(dp)了,时间复杂度最大为(O(50^4))
    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    #define il inline
    #define vocaloid(v) (v>='0'&&v<='9')
    template <typename T>
    il void read(T &x)
    {
    	x=0;char v=getchar();
    	while(!vocaloid(v)) v=getchar();
    	while(vocaloid(v)) {x=(x<<1)+(x<<3)+v-'0';v=getchar();}
    }
    int n,m,f[59][59][59][59];
    int a[399],g[7];
    il int dfs(int i,int j,int p,int q)//记忆化搜索
    {
    	if(f[i][j][p][q]) return f[i][j][p][q];
    	if(i==g[1]&&j==g[2]&&p==g[3]&&q==g[4]) return 0;
    	int x=1+1*i+2*j+3*p+4*q;
    	int Max=0;
    	if(i<g[1]) Max=max(Max,dfs(i+1,j,p,q)+a[x+1]);
    	if(j<g[2]) Max=max(Max,dfs(i,j+1,p,q)+a[x+2]);
    	if(p<g[3]) Max=max(Max,dfs(i,j,p+1,q)+a[x+3]);
    	if(q<g[4]) Max=max(Max,dfs(i,j,p,q+1)+a[x+4]);
    	return f[i][j][p][q]=Max;
    }
    int main()
    {
    	freopen("tortoise.in","r",stdin);
    	freopen("tortoise.out","w",stdout);
    	read(n),read(m);int ser;
    	for(int i=1;i<=n;i++)	read(a[i]);
    	for(int i=1;i<=m;i++)
    		read(ser),g[ser]++;
    	/*f[0][0][0][0]=a[1];//动态规划
    	for(int i=0;i<=g[1];i++)
    		for(int j=0;j<=g[2];j++)
    			for(int p=0;p<=g[3];p++)
    				for(int q=0;q<=g[4];q++)
    				{
    					if(i==0&&j==0&&p==0&&q==0) continue ;
    					int Max=0,x=1+1*i+2*j+3*p+4*q;
    					if(i>0) Max=max(Max,f[i-1][j][p][q]+a[x]);
    					if(j>0) Max=max(Max,f[i][j-1][p][q]+a[x]);
    					if(p>0) Max=max(Max,f[i][j][p-1][q]+a[x]); 
    					if(q>0) Max=max(Max,f[i][j][p][q-1]+a[x]);
    					f[i][j][p][q]=max(Max,f[i][j][p][q]);
    				}
    	printf("%d
    ",f[g[1]][g[2]][g[3]][g[4]]);*/
    	printf("%d
    ",dfs(0,0,0,0)+a[1]);
    	return 0;
    }
    
  • 相关阅读:
    mysql 安装及基本点
    logback中的additivity属性
    chrome中,拖动.crx无响应
    Java安装
    mysql多表连接的几种写法
    Ionic -- Refresher & InfiniteScroll 下拉刷新与滚动懒加载
    ng-cli + ionic-cli 常用命令
    Vue笔记(五):Vuex
    JavaScript设计模式(三):发布—订阅模式(观察者模式)
    Windows下解决项目未正确关闭引起的nodejs端口占用
  • 原文地址:https://www.cnblogs.com/MIKU5201314/p/14086713.html
Copyright © 2020-2023  润新知