搜索巨合集

搜索巨合集


noip即将到来

然而 蒟蒻BJ还连搜索都打不明白


这篇blog将会记录一些搜索题

希望能对您有所助力

1215: [HNOI2003]24点游戏

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 226  Solved: 61
[Submit][Status][Discuss]

Description

为了培养小孩的计算能力,大人们经常给小孩玩这样的游戏:从1付扑克牌中任意抽出4张扑克,要小孩用“+”、“-”、“×”、“÷”和括号组成一个合法的表达式,并使表达式的值为24点。这种游戏就是所谓的“24点游戏”。请你编程求出对于给出的任意4个正整数a、b、c、d,请你编程求出这4个整数能组成多少个值为24的不同表达式。

Input

输入共一行,为4个正整数a、b、c、d (0<=a,b,c,d<=100)

Output

输出由a、b、c、d组成的值为24表达式个数,如没有,输出0。

Sample Input

5 5 5 5

Sample Output

1

这。。。应该算搜索水题???

需药就是枚举

先枚举数字的顺序

再枚举每个运算符号

然后是枚举运算先后 即怎么加括号

但是方案数并不能这么开心的得到

所以哈希一下,最后判个重

全靠暴力 锻炼暴力能力!!!


#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<map>
#include<set>
using namespace std;

typedef double db;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}

const db eps=1e-9;

int a[5],r[5],v[5],tot,hs[8000];

bool used[5];

inline void insert(int x1,int x2,int x3,int x4,int x5,int x6,int x7)
{hs[++tot]=x1|x2<<3|x3<<6|x4<<9|x5<<12|x6<<15|x7<<18;}

inline db opt(db x,db y,int o)
{
	if(o==0)return x+y;
	if(o==1)return x-y;
	if(o==2)return x*y;
	return x/y;
}

inline bool can(int x,int y)
{
	if(x==0)return y>1;
	if(x==2)return y<2;
	return 1;
} 

void check()
{
	for(int i=0;i<4;++i)
		for(int j=0;j<4;++j)
			for(int k=0;k<4;++k)
			{
				bool c1=can(k,j),c2=can(j,i);
				
				if(abs(opt(opt(opt(a[v[1]],a[v[2]],i),a[v[3]],j),a[v[4]],k)-24)<eps)
					insert(r[v[1]],r[v[2]],i+4,r[v[3]],j+4,r[v[4]],k+4);
				
				if(c1&&abs(opt(opt(a[v[1]],a[v[2]],i),opt(a[v[3]],a[v[4]],j),k)-24)<eps)
					insert(r[v[1]],r[v[2]],i+4,r[v[3]],r[v[4]],j+4,k+4);
				
				if(c2&&abs(opt(opt(a[v[1]],opt(a[v[2]],a[v[3]],i),j),a[v[4]],k)-24)<eps)
					insert(r[v[1]],r[v[2]],r[v[3]],i+4,j+4,r[v[4]],k+4);
				
				if(c1&&abs(opt(a[v[1]],opt(opt(a[v[2]],a[v[3]],i),a[v[4]],j),k)-24)<eps)
					insert(r[v[1]],r[v[2]],r[v[3]],i+4,r[v[4]],j+4,k+4);
				
				if(c1&&c2&&abs(opt(a[v[1]],opt(a[v[2]],opt(a[v[3]],a[v[4]],i),j),k)-24)<eps)
					insert(r[v[1]],r[v[2]],r[v[3]],r[v[4]],i+4,j+4,k+4);
			}
}

void pre_dfs(int step)
{
	if(step>4)
	{
		check();
		return ;
	}
	for(int i=0;i<4;++i)
	{
		if(used[i])continue;
			used[i]=1;v[step]=i;
			pre_dfs(step+1);
			used[i]=0;
	}
}

int main()
{
	a[0]=read();a[1]=read();a[2]=read();a[3]=read();
	for(int i=0;i<4;++i)
		for(int j=0;j<4;++j)
			r[i]+=a[i]<a[j];
	
	pre_dfs(1);
	
	sort(hs+1,hs+1+tot);
	
	int ans=0;
	if(tot)ans=1;
	for(int i=2;i<=tot;++i)if(hs[i]^hs[i-1])ans++;
	print(ans);puts("");
	return 0;
}
/*
5 5 5 5

1
*/

题目描述

小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他

们想用数独来一比高低。但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教,

Z 博士拿出了他最近发明的“靶形数独”,作为这两个孩子比试的题目。

靶形数独的方格同普通数独一样,在 9 格宽×9 格高的大九宫格中有 9 个 3 格宽×3 格

高的小九宫格(用粗黑色线隔开的)。在这个大九宫格中,有一些数字是已知的,根据这些数字,利用逻辑推理,在其他的空格上填入 1 到 9 的数字。每个数字在每个小九宫格内不能

重复出现,每个数字在每行、每列也不能重复出现。但靶形数独有一点和普通数独不同,即

每一个方格都有一个分值,而且如同一个靶子一样,离中心越近则分值越高。(如图)

上图具体的分值分布是:最里面一格(黄色区域)为 10 分,黄色区域外面的一圈(红

色区域)每个格子为 9 分,再外面一圈(蓝色区域)每个格子为 8 分,蓝色区域外面一圈(棕

色区域)每个格子为 7 分,最外面一圈(白色区域)每个格子为 6 分,如上图所示。比赛的

要求是:每个人必须完成一个给定的数独(每个给定数独可能有不同的填法),而且要争取

更高的总分数。而这个总分数即每个方格上的分值和完成这个数独时填在相应格上的数字

的乘积的总和

总分数即每个方格上的分值和完成这个数独时填在相应格上的数字

的乘积的总和。如图,在以下的这个已经填完数字的靶形数独游戏中,总分数为 2829。游戏规定,将以总分数的高低决出胜负。

由于求胜心切,小城找到了善于编程的你,让你帮他求出,对于给定的靶形数独,能

够得到的最高分数。

输入输出格式

输入格式:

 

一共 9 行。每行 9 个整数(每个数都在 0―9 的范围内),表示一个尚未填满的数独方

格,未填的空格用“0”表示。每两个数字之间用一个空格隔开。

 

输出格式:

 

输出文件 sudoku.out 共 1 行。

输出可以得到的靶形数独的最高分数。如果这个数独无解,则输出整数-1。

 

输入输出样例

输入样例#1:
sudoku1
7 0 0 9 0 0 0 0 1 
1 0 0 0 0 5 9 0 0 
0 0 0 2 0 0 0 8 0 
0 0 5 0 2 0 0 0 3 
0 0 0 0 0 0 6 4 8 
4 1 3 0 0 0 0 0 0 
0 0 7 0 0 2 0 9 0 
2 0 1 0 6 0 8 0 4 
0 8 0 5 0 4 0 1 2

sudoku2
0 0 0 7 0 2 4 5 3 
9 0 0 0 0 8 0 0 0 
7 4 0 0 0 5 0 1 0 
1 9 5 0 8 0 0 0 0 
0 7 0 0 0 0 0 2 5 
0 3 0 5 7 9 1 0 8 
0 0 0 6 0 1 0 0 0 
0 6 0 9 0 0 0 0 1 
0 0 0 0 0 0 0 0 6
输出样例#1:
sudoku1
2829

sudoku2
2852

说明

【数据范围】

40%的数据,数独中非 0 数的个数不少于 30。

80%的数据,数独中非 0 数的个数不少于 26。

100%的数据,数独中非 0 数的个数不少于 24。

NOIP 2009 提高组 第四题



以为会搜的很复杂

结果一看大家都是直接枚举每个位置填啥。。。

然后我就也这么写了。。。

然后再优化一下 就完了。。。


#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<map>
#include<set>
using namespace std;

typedef long long ll;

inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return f*x;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}

const int N=10;

int a[N][N],col[N][N],ans,res,remain=81;
bool row[N][N],column[N][N],square[N][N];

inline int getscore(int x,int y,int val)
{
	if(x==5&&y==5)return val*10;
	if(x>=4&&y>=4&&x<=6&&y<=6)return val*9;
	if(x>=3&&y>=3&&x<=7&&y<=7)return val*8;
	if(x>=2&&y>=2&&x<=8&&y<=8)return val*7;
	return val*6;
}

inline bool fill(int x,int y,int val)
{
	if(row[x][val])return 0;
	if(column[y][val])return 0;
	if(square[(x-1)/3*3+(y-1)/3+1][val])return 0;
	row[x][val]=column[y][val]=square[(x-1)/3*3+(y-1)/3+1][val]=1;
	col[x][y]=val;
	res+=getscore(x,y,val);remain--;
	return 1;
}

inline void del(int x,int y,int val)
{
	res-=getscore(x,y,val);
	row[x][val]=column[y][val]=square[(x-1)/3*3+(y-1)/3+1][val]=0;
	col[x][y]=0;remain++;
}

const int lala=5*int(1e6);

int tim;

void dfs(int x,int y)
{
	if(++tim>lala)return ;
	if(ans>remain*81+res)return ;
	if(x==10){ans=max(ans,res);return ;}
	if(col[x][y]){y==9?dfs(x+1,1):dfs(x,y+1);}
	else 
	{//cout<<x<<" "<<y<<endl;
		for(int i=1;i<=9;++i)
		{
			if(fill(x,y,i))
			{//cout<<x<<" "<<y<<" "<<res<<" "<<endl;
				y==9?dfs(x+1,1):dfs(x,y+1);
				del(x,y,i);
			}
		}
	}
}

int main()
{
	for(int i=9;i>=1;--i)for(int j=9;j>=1;--j)
	{
		a[i][j]=read();
		if(a[i][j])fill(i,j,a[i][j]);
	}
	dfs(1,1);
	memset(col,0,sizeof(col));
	memset(row,0,sizeof(row));memset(column,0,sizeof(column));
	memset(square,0,sizeof(square));
	res=tim=0;remain=81;
	for(int i=9;i>=1;--i)for(int j=1;j<=9;++j)
	{
		if(a[i][j])fill(9-j+1,i,a[i][j]);
	}
	dfs(1,1);
	if(ans)cout<<ans<<endl;
	else puts("-1");
	return 0;
}
/*
sudoku1
7 0 0 9 0 0 0 0 1
1 0 0 0 0 5 9 0 0
0 0 0 2 0 0 0 8 0
0 0 5 0 2 0 0 0 3
0 0 0 0 0 0 6 4 8
4 1 3 0 0 0 0 0 0
0 0 7 0 0 2 0 9 0
2 0 1 0 6 0 8 0 4
0 8 0 5 0 4 0 1 2

2829

sudoku2
0 0 0 7 0 2 4 5 3
9 0 0 0 0 8 0 0 0
7 4 0 0 0 5 0 1 0
1 9 5 0 8 0 0 0 0
0 7 0 0 0 0 0 2 5
0 3 0 5 7 9 1 0 8
0 0 0 6 0 1 0 0 0
0 6 0 9 0 0 0 0 1
0 0 0 0 0 0 0 0 6

2852
*/

描述

小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次。于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间。

小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的:

  1. 在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的;

  2. 有些棋子是固定的,有些棋子则是可以移动的;

  3. 任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。 游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。

给定一个棋盘,游戏可以玩 q 次,当然,每次棋盘上固定的格子是不会变的,但是棋盘上空白的格子的初始位置、指定的可移动的棋子的初始位置和目标位置却可能不同。第 i 次玩的时候,空白的格子在第  EXi 行第  EYi  列,指定的可移动棋子的初始位置为第  SXi  行第  SYi  列,目标位置为第  TXi  行第  TYi  列。

假设小 B 每秒钟能进行一次移动棋子的操作,而其他操作的时间都可以忽略不计。请你告诉小 B 每一次游戏所需要的最少时间,或者告诉他不可能完成游戏。

格式

输入格式

第一行有 3 个整数,每两个整数之间用一个空格隔开,依次表示 n、m 和 q;

接下来的 n 行描述一个 n*m 的棋盘,每行有 m 个整数,每两个整数之间用一个空格隔开,每个整数描述棋盘上一个格子的状态,0 表示该格子上的棋子是固定的,1 表示该格子上的棋子可以移动或者该格子是空白的。

接下来的 q 行,每行包含 6 个整数依次是  EXi EYi SXi SYi TXi TYi ,每两个整数之间用一个空格隔开,表示每次游戏空白格子的位置,指定棋子的初始位置和目标位置。

输出格式

输出有 q 行,每行包含 1 个整数,表示每次游戏所需要的最少时间,如果某次游戏无法完成目标则输出−1。

样例1

样例输入1[复制]

3 4 2 
0 1 1 1 
0 1 1 0 
0 1 0 0 
3 2 1 2 2 2 
1 2 2 2 3 2

样例输出1[复制]

2 
-1

限制

每个测试点1s。

提示

样例说明

棋盘上划叉的格子是固定的,红色格子是目标位置,圆圈表示棋子,其中绿色圆圈表示目标棋子。

  1. 第一次游戏,空白格子的初始位置是 (3, 2)(图中空白所示),游戏的目标是将初始位置在(1, 2)上的棋子(图中绿色圆圈所代表的棋子)移动到目标位置(2, 2)(图中红色的格子)上。

    移动过程如下:

    img

  2. 第二次游戏,空白格子的初始位置是(1, 2)(图中空白所示),游戏的目标是将初始位置在(2, 2)上的棋子(图中绿色圆圈所示)移动到目标位置 (3, 2)上。

    img

    要将指定块移入目标位置,必须先将空白块移入目标位置,空白块要移动到目标位置,必然是从位置(2,2)上与当前图中目标位置上的棋子交换位置,之后能与空白块交换位置的只有当前图中目标位置上的那个棋子,因此目标棋子永远无法走到它的目标位置,游戏无法完成。


先给一个爆搜版(现在被挤到下面去了。。)

以白块和指定棋子的状态为状态进行宽搜

具体就是:

考虑无脑搜索,直接狂挪白块,然而这样并没有什么用,并不知道指定块怎么搞

所以既然不知道指定块怎么搞,就把它加到状态里就好啦

每次爆搜,白块和指定块的位置都是nm所以最后复杂度O((nm)^2)

感觉思路还是不错的。。。(因为博主傻 这都没想到)


之后是正解:

NOIP2013 华容道 解题报告(题解写的挺好的,就是语言是Pascal)

代码的话,觉得我写的还说的过去


#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<set>
#include<map>
using namespace std;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}

const int N=4010,M=400100,inf=0X3f3f3f3f;
const int xx[4]={-1,1,0,0},yy[4]={0,0,-1,1};

int last[N],ecnt;
struct EDGE{int to,nt,val;}e[M];
inline void add(int u,int v,int val)
{e[++ecnt]=(EDGE){v,last[u],val};last[u]=ecnt;}

int n,m,mp[40][40];

int d[40][40];

int q[N][2];

void bfs(int si,int sj,int ti,int tj,int dir)
{
	memset(d,0,sizeof(d));
	register int i,j,x,y,k,head=0,tail=1;
	q[0][0]=si,q[0][1]=sj;d[si][sj]=1;
	
	while(head^tail)
	{
		i=q[head][0],j=q[head++][1];
		for(k=0;k<4;++k)
		{
			x=i+xx[k];y=j+yy[k];
			if(!mp[x][y]||d[x][y]||(x==ti&&y==tj))continue;
			d[x][y]=d[i][j]+1;
			q[tail][0]=x;q[tail++][1]=y;
		}
	}
	if(dir==4)return ;
	for(k=0;k<4;++k)
	{
		x=ti+xx[k];y=tj+yy[k];
		if((i==si&&j==sj)||!d[x][y])continue;
		add(ti*30*4+tj*4+dir,ti*30*4+tj*4+k,d[x][y]-1);
	}
	add(ti*30*4+tj*4+dir,si*30*4+sj*4+(dir^1),1);
}

int dis[N],Q[N];
bool inq[N];

void spfa(int si,int sj)
{
	memset(dis,0X3f,sizeof(dis));
	register int head=0,tail=0,i,k,x,y,u;
	for(k=0;k<4;++k)
	{
		x=si+xx[k];y=sj+yy[k];
		if(!d[x][y])continue;
		u=si*30*4+sj*4+k;
		Q[tail++]=u;inq[u]=1;
		dis[u]=d[x][y]-1;
	}
	while(head^tail)
	{
		u=Q[head++];inq[u]=0;head%=N;
		for(i=last[u];i;i=e[i].nt)
		if(dis[e[i].to]>dis[u]+e[i].val)
		{
			dis[e[i].to]=dis[u]+e[i].val;
			if(!inq[e[i].to])inq[e[i].to]=1,Q[tail++]=e[i].to,tail%=N;
		}
	}
}

void initial()
{
	register int i,j,k,x,y;
	for(i=1;i<=n;++i)for(j=1;j<=m;++j)
	if(mp[i][j])
	{
		for(k=0;k<4;++k)
		{
			x=i+xx[k];y=j+yy[k];
			if(mp[x][y])bfs(x,y,i,j,k);
		}
	}
}

int main()
{
	n=read();m=read();int Q=read();
	register int i,j,k,ei,ej,si,sj,ti,tj,ans;
	for(i=1;i<=n;++i)for(j=1;j<=m;++j)
		mp[i][j]=read();
	initial();
	while(Q--)
	{
		ei=read(),ej=read(),si=read(),sj=read(),ti=read(),tj=read();
		if(si==ti&&sj==tj){puts("0");continue;}
		bfs(ei,ej,si,sj,4);spfa(si,sj);
		ans=inf;
		for(k=0;k<4;++k)
			ans=min(ans,dis[ti*30*4+tj*4+k]);
		if(ans^inf){print(ans);puts("");}
		else puts("-1");
	}
	return 0;
}
/*
3 4 2
0 1 1 1
0 1 1 0
0 1 0 0
3 2 1 2 2 2
1 2 2 2 3 2

2
-1
*/


附赠80分代码

#include <cstdio>
#include <cstring>
#define MAXN 35

const int vx[4] = {0, 0, 1, -1}, vy[4] = {1, -1, 0, 0};

int n, m, t, a[MAXN][MAXN], vis[MAXN][MAXN][MAXN][MAXN];
int ex, ey, sx, sy, tx, ty;

struct Queue 
{
    int x, y, ox, oy, d;
} q[MAXN * MAXN * MAXN * MAXN];

int BFS() 
{
    int h = 1, t = 2;
    q[1] = (Queue) {ex, ey, sx, sy, 0};
	
    while (h != t) 
	{
        for (int i = 0; i <= 3; i++) 
		{
            int nx = q[h].x + vx[i], ny = q[h].y + vy[i];
            if (nx == q[h].ox && ny == q[h].oy) 
			{
                q[t].ox = q[h].x, q[t].oy = q[h].y;
                if (q[t].ox == tx && q[t].oy == ty) return q[h].d + 1;
            }
            else q[t].ox = q[h].ox, q[t].oy = q[h].oy;
			
            if (!a[nx][ny] || vis[nx][ny][q[t].ox][q[t].oy]) continue;
			
            vis[nx][ny][q[t].ox][q[t].oy] = 1;
            q[t].x = nx, q[t].y = ny, q[t].d = q[h].d + 1;
            t++;
        }
        h++;
    }
    return -1;
}

int main() 
{
    scanf("%d %d %d", &n, &m, &t); 	
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
			scanf("%d", &a[i][j]);
    for (int i = 1; i <= t; i++)
	{
        memset(vis, 0, sizeof(vis));
        scanf("%d %d %d %d %d %d", &ex, &ey, &sx, &sy, &tx, &ty);
        vis[ex][ey][sx][sy] = 1;
        printf("%d\n", sx == tx && sy == ty ? 0 :BFS());
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值