[kuangbin带你飞]专题一 简单搜索(大全)

密码:123456

目录

    • A - Dungeon Master
    • B - Catch That Cow
    • C - Fliptile
    • D - Find The Multiple
    • E - Prime Path
    • F - Shuffle'm Up
    • G - Pots
    • H - Oil Deposits
    • I - 非常可乐
    • J - Find a way
    • K - 马走日
    • L - 海贼王之伟大航路
    • M - 迷宫问题
    • N - 鸣人和佐助
    • O - 红与黑
    • P - 棋盘问题
    • Q - 拯救行动
    • R - Saving Tang Monk
    • S - Fire Game
    • T - Fire!
    • U - Cops and Robbers

A - Dungeon Master

A - Dungeon Master

题意:
 给你一个三维空间,’.‘表示可以通过,’#'表示不能通过,求从起点’S’到终点’E’的最短路径。

题解:
 裸bfs,每次可以往六个方向移动,30 * 30 * 30用dfs会TLE。

AC_Code:

#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 35;
char a[maxn][maxn][maxn];
bool vis[maxn][maxn][maxn];
int step[maxn][maxn][maxn];
int num = 0;
int n,m,h;
int startX, startY, startZ, endX, endY, endZ;
const int Move[6][3] = {{0,0,1},{0,0,-1},{0,1,0},{0,-1,0},{1,0,0},{-1,0,0}};
int minn;

struct node{
	int x,y,z;//高,行,列
	int step;
};

queue<node>q;
node st;
node End;

void init(){
	while(!q.empty()) q.pop();
	memset(vis,false,sizeof(vis));
	st.x = 0; st.y = 0; st.z = 0; st.step = 0;
	End.x = 0; End.y = 0; End.z = 0; End.step = 0;
}

inline bool check(int x, int y, int z){
	if ((x >= 0) && (x < h) && (y >= 0) && (y < n) && (z >= 0) && (z < m) && (!vis[x][y][z]) && (a[x][y][z] == '.' || a[x][y][z] == 'E'))
		return true;
	else
		return false;
}

void bfs(){
	node cur;
	q.push(st);
	while(!q.empty()){
		cur = q.front();
		q.pop();
		if(cur.x == End.x && cur.y == End.y && cur.z == End.z){
			printf("Escaped in %d minute(s).\n",cur.step);
			return;
		}
		vis[cur.x][cur.y][cur.z] = true;
		for(int i=0; i<6; ++i){
			node new_cur;
			new_cur.x = cur.x + Move[i][0];
			new_cur.y = cur.y + Move[i][1];
			new_cur.z = cur.z + Move[i][2];
			if(check(new_cur.x, new_cur.y, new_cur.z)){
				new_cur.step = cur.step + 1;
				q.push(new_cur);
				vis[new_cur.x][new_cur.y][new_cur.z] = true;
			}
		}
	}
	printf("Trapped!\n");
}


int main(){
	while(~scanf("%d%d%d",&h,&n,&m)){//高,行,列
		if(n == 0 && m == 0 && h == 0) break;
		init();
		for(int z=0; z<h; ++z){
			getchar();
			for(int i=0; i<n; ++i){
				for(int j=0; j<m; ++j){
					scanf("%c",&a[z][i][j]);
					if(a[z][i][j] == 'S'){
						st.x = z;
						st.y = i;
						st.z = j;
						st.step = 0;
					}
					if(a[z][i][j] == 'E'){
						End.x = z;
						End.y = i;
						End.z = j;
					}
				}
				getchar();
			}
		}
		bfs();
	}
}

B - Catch That Cow

B - Catch That Cow

题意:
 在数轴上定一个起点和终点,每一次可以从点X运动到X+1或者X-1或者2*X,问从起点到终点最少需要的步数。(PS:X不能运动到X<0或者X>100000)

题解:
 裸bfs。

//
//Write by Yuan Xilan on 2019...
//
#include 
#include 
#include 
#include 
#include 
using namespace std;

const int maxn = 3e5+10;
int n,k;
struct node{
	int x;
	int step;
};
node a;
queue<node>q;
bool vis[maxn];
int minn;

void init(){
	while(!q.empty()) q.pop();
	a.x = n; a.step = 0;
	memset(vis,false,sizeof(vis));
	minn = 0x3f3f3f3f;
}

bool judge(int x){
	if(x >= 0 && x <= 100000) return true;
	return false;
}

void bfs(){
	q.push(a);
	while(!q.empty()){
		node m = q.front();
		q.pop();
		vis[m.x] = true;
		if(m.x == k){
			printf("%d\n",m.step);
			return;
		}
		
		node y;
		y.x = m.x + 1;
		if(!vis[y.x] && judge(y.x)){
			y.step = m.step + 1;
			q.push(y);
			vis[y.x] = true;
		}

		y.x = m.x - 1;
		if(!vis[y.x] && judge(y.x)){
			y.step = m.step + 1;
			q.push(y);
			vis[y.x] = true;
		}

		y.x = m.x * 2;
		if(!vis[y.x] && judge(y.x)){
			y.step = m.step + 1;
			q.push(y);
			vis[y.x] = true;
		}
	}
}

int main(){
	while(~scanf("%d%d",&n,&k)){
		init();
		bfs();
	}
}

C - Fliptile

C - Fliptile

题意:
 有M行N列盏灯,状态为1表示开灯,状态为0表示关灯,每次可对坐标为(x,y)的灯进行一次操作,那么(x-1,y),(x+1,y),(x,y-1),(x,y+1),(x,y)这五盏灯在状态为1时会变为0,在状态为0时,问最少的操作次数,使得最终所有灯的状态均为0,如果不存在输出"IMPOSSIBLE"。

题解:
 当第一行的灯的状态确定后,第2到M行灯是否操作都已经确定,举个例子,如果第一行的灯状态为0 1 1 0,第二行的灯状态为1 1 0 1,那么,为了使第一行的第二个灯状态变为0,需要对第二行第二列的灯进行一次操作,为了使第一行的第三个灯状态变为0,需要对第二行第三列的灯进行一次操作,由于上一行的灯的状态只受(i+1,j)灯泡的影响,所以,结论正确。

 因此,我们只要枚举所有第一行所有操作的情况,然后判断最后一行是否全为0即可。(因为我们第二行的操作是成全第一行全为0,第三行的操作是成全第二行全为0,…,最后一行的操作是成全倒数第二行全为0)

 每个灯的状态有0和1两种,那么m个灯的状态就是2m个情况,所以我们在枚举时可以结合二进制一起考虑,也就是1<

AC_Code:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
int n,m;

bool vis[205][205];
char s[205][205];
char a[205][205];
char b[205][205];
char c[205][205];
const int Move[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};

void filp(int i, int j){
	if(i > 0) b[i-1][j] = (b[i-1][j] == '0' ? '1' : '0');
	if(j > 0) b[i][j-1] = (b[i][j-1] == '0' ? '1' : '0');
	if(i + 1 < n) b[i+1][j] = (b[i+1][j] == '0' ? '1' : '0');
	if(j + 1 < m) b[i][j+1] = (b[i][j+1] == '0' ? '1' : '0');
	b[i][j] = (b[i][j] == '0' ? '1' : '0');
}

int main(){
	while(~scanf("%d%d",&n,&m)){
		for(int i=0; i<n; ++i){
			for(int j=0; j<m; ++j){
				getchar();
				scanf("%c",&a[i][j]);
			}
		}
		int minn = 0x3f3f3f3f;
		for(int i=0; i<(1<<m); ++i){
			memset(c,0,sizeof(c));
			memcpy(b,a,sizeof(b));
			int cnt = 0;
			for(int j=m-1; j>=0; --j){
				if((i>>(m-1-j)&1) == 1){
					c[0][j] = '1';
					filp(0,j);
					cnt += 1;
				}
				else{
					c[0][j] = '0';
				}
			}

			for(int ii=1; ii<n; ++ii){
				for(int jj=0; jj<m; ++jj){
					if(b[ii-1][jj] == '1'){
						filp(ii,jj);
						c[ii][jj] = '1';
						cnt += 1;
					}
					else c[ii][jj] = '0';
				}
			}

			bool flag = true;
			for(int kk=0; kk<m; ++kk){
				if(b[n-1][kk] == '1'){
					flag = false;
					break;
				}
			}
			if(!flag) continue;
			if(cnt < minn){
				minn = cnt;
				memcpy(s,c,sizeof(s));
			}
		}
		if(minn == 0x3f3f3f3f) cout << "IMPOSSIBLE\n";
		else{
			for(int i=0; i<n; ++i){
				for(int j=0; j<m; ++j){
					if(j != m-1)
						cout << s[i][j] << " ";
					else cout<< s[i][j] << endl;
				}
			}
		}
	}
}

D - Find The Multiple

D - Find The Multiple

题意:
 给定一个正整数n,请编写一个程序来寻找n的一个非零的倍数m,这个m应当在十进制表示时每一位上只包含0或者1。

题解:
 这道题一开始以为位数会很大,然后看到别人开了long long就过了…由于输出任意一个满足即可,从1开始跑bfs即可。

AC_Code:

//
//Write by Yuan Xilan on 2019...
//
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SZ(X) ((int)(X).size())
#define ALL(X) (X).begin(), (X).end()
#define REP(I, N) for (int I = 0; I < (N); ++I)
#define REPP(I, A, B) for (int I = (A); I < (B); ++I)
#define FOR(I, A, B) for (int I = (A); I <= (B); ++I)
#define FORS(I, S) for (int I = 0; S[I]; ++I)
#define RS(X) scanf("%s", (X))
#define SORT_UNIQUE(c) (sort(c.begin(),c.end()), c.resize(distance(c.begin(),unique(c.begin(),c.end()))))
#define GET_POS(c,x) (lower_bound(c.begin(),c.end(),x)-c.begin())
#define CASET int ___T; scanf("%d", &___T); for(int cs=1;cs<=___T;cs++)
#define MP make_pair
#define PB push_back
#define MS0(X) memset((X), 0, sizeof((X)))
#define MS1(X) memset((X), -1, sizeof((X)))
#define LEN(X) strlen(X)
#define F first
#define S second
using namespace std;
typedef long long ll,LL;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef vector<LL> VL;
typedef vector<PII> VPII;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;
void R() {}
#ifdef HOME
 #define DEBUG(...) {printf("# ");printf(__VA_ARGS__);puts("");}
#else
 #define DEBUG(...)
#endif
const int maxn = 1555510;
ll a[maxn],b[maxn];
int mod = 1e9+7;
ll n;
struct node{
	ll s;	
};
node c;

queue<node>q;

void bfs(){
	q.push(c);
	node d;
	while(!q.empty()){
		d = q.front();
		if(d.s % n == 0){
			cout << d.s << endl;
			return;
		}
		q.pop();
		node e = d;
		e.s = d.s * 10;
		q.push(e);
		e.s = d.s * 10 + 1;
		q.push(e);
	}
}

int main(){
	while(~scanf("%lld",&n) && n){
		c.s = 1LL;
		while(!q.empty()) q.pop();
		bfs();	
	}
}

E - Prime Path

E - Prime Path

题意:
 给你两个四位的素数a,b。a可以改变某一位上的数字变成c,但只有当c也是四位的素数时才能进行这种改变。询问计算a最少经过多少次上述变换才能变成b。

题解:
 这道题做得还是挺坎坷的,先将1000到10000的素数先打表,可O(1)判断素数,接下来对每一位进行bfs即可。

AC_Code:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
 
struct node{
	char s[10];
	int step;
};
node a,b;
queue<node>q;
int minn;
bool v[10005];
int m[10005];
 
void init(){
	a.step = 0;b.step = 0;
	minn = 0x3f3f3f3f;
	memset(m,0,sizeof(m));
	while(!q.empty()) q.pop();
}
 
int ex_change(char s[]){
	int num = 0, cnt = 3;
	for(int i=0; i<strlen(s); ++i){
		num += (s[i]-'0') * int(pow(10,cnt--));
	}
	return num;
}
 
bool judge(char a1[], char a2[]){
	int len = strlen(a1);
	if(len != strlen(a2)) return false;
	for(int i=0; i<len; ++i){
		if(a1[i] != a2[i]) return false;
	}
	return true;
}
 
void bfs(){
	q.push(a);
	node c;
	while(!q.empty()){
		c = q.front();
		q.pop();
		m[ex_change(c.s)] += 1;
		//cout << b.s << " " << c.s << " " << judge(b.s,c.s) << endl;
		//cout << strcmp(b.s,c.s) << endl;
		if(!strcmp(b.s,c.s)){
			printf("%d\n",c.step);
			return;
		}
		for(int i=0; i<4; ++i){
			for(int j=0; j<10; ++j){
				node new_c = c;
				new_c.s[i] = '0' + j;
				if(new_c.s[0] == '0') continue;
				if(!v[ex_change(new_c.s)] || m[ex_change(new_c.s)]) continue;
				m[ex_change(new_c.s)] += 1;
				new_c.step = c.step + 1;
				q.push(new_c);
			} 
		}
	}
	printf("Impossible\n");
}
 
int main(){
	int t;
	for(int i=1000; i<10000; ++i){
		bool flag = true;
		for(int j=2; j*j<=i; ++j){
			if(i%j==0){
				flag = false;
				break;
			}
		}
		if(flag) v[i] = true;
	}
	scanf("%d",&t);
	while(t--){
		init();
		scanf("%s",a.s);
		scanf("%s",b.s);
		bfs();
	}
}

F - Shuffle’m Up

F - Shuffle’m Up

题意:
 给你三个字符串,问第一个字符串和第二个字符串是否可以通过变换,组合成第三个字符串,变换规则如下:假设s1=12345,s2=67890,变换后的序列 s=6172839405,s1=61728,s2=39405

题解:
 map水过,如果在变换过程中组合成的字符串在前面出现过,那么它将陷入一个“死循环”,永远组合不成目标字符串。

//
//Write by Yuan Xilan on 2019...
//
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SZ(X) ((int)(X).size())
#define ALL(X) (X).begin(), (X).end()
#define REP(I, N) for (int I = 0; I < (N); ++I)
#define REPP(I, A, B) for (int I = (A); I < (B); ++I)
#define FOR(I, A, B) for (int I = (A); I <= (B); ++I)
#define FORS(I, S) for (int I = 0; S[I]; ++I)
#define RS(X) scanf("%s", (X))
#define SORT_UNIQUE(c) (sort(c.begin(),c.end()), c.resize(distance(c.begin(),unique(c.begin(),c.end()))))
#define GET_POS(c,x) (lower_bound(c.begin(),c.end(),x)-c.begin())
#define CASET int ___T; scanf("%d", &___T); for(int cs=1;cs<=___T;cs++)
#define MP make_pair
#define PB push_back
#define MS0(X) memset((X), 0, sizeof((X)))
#define MS1(X) memset((X), -1, sizeof((X)))
#define LEN(X) strlen(X)
#define F first
#define S second
using namespace std;
typedef long long ll,LL;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef vector<LL> VL;
typedef vector<PII> VPII;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;
void R() {}
#ifdef HOME
 #define DEBUG(...) {printf("# ");printf(__VA_ARGS__);puts("");}
#else
 #define DEBUG(...)
#endif
const int maxn = 10;
int mod = 1e9+7;
int n,num;
struct node{
	
};
queue<node>q;
int startX, startY;
const int Move[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
bool vis[maxn][maxn];
map<string, int>m;
int fath[100100];
int len;
node a;
string s1;
string s2;
string s3;
string s;

int main(){
	int t;
	while(~scanf("%d",&t)){
		int cnt = 0;
		while(t--){
			m.clear();
			cin >> len;
			cin >> s1 >> s2 >> s3;
			int num = 1;
			while(1){
				s = "";
				for(int i=0; i<len; ++i){
					s += s2[i];
					s += s1[i];
				}
				if(s == s3){
					cout << ++cnt << " " << num << endl;
					break;
				}
				num += 1;
				if(m[s]){
					cout << ++cnt << " " << -1 << endl;
					break;
				}
				m[s] += 1;
				for(int i=0; i<len; ++i) s1[i] = s[i];
				for(int i=0; i<len; ++i) s2[i] = s[i+len];
			}
		}
	}
}

G - Pots

G - Pots

题意:
 给定两个容器,问最少需要多少次操作可以使得任意一个杯子中体积为C,如果不存在输出-1.

题解:
 裸bfs,在结构体中用father记录父代,最终递归输出即可。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
int a,b,c;

void choose(int x){
	if(x == 1) puts("FILL(1)");
	else if(x == 2) puts("FILL(2)");
	else if(x == 3) puts("POUR(1,2)");
	else if(x == 4) puts("POUR(2,1)");
	else if(x == 5) puts("DROP(1)");
	else if(x == 6) puts("DROP(2)");
}

bool vis[105][105];

struct node
{
	int left;
	int right;
	int father;
	int ope;
	/*
	node(int l, int r, int fa){
		left = l;
		right = r;
		father = fa;
	}
	*/
};

node q[20000];
int head = 0; 
int tail = 0;
int times = 0;

void print(node k){
	times += 1;
	if(k.father != -1){
		print(q[k.father]);
	}
	if(k.father == -1) cout << --times << endl;
	choose(k.ope);
}

void init(){
	memset(vis,0,sizeof(vis));
	memset(q,0,sizeof(q));
	head = 0;
	tail = 0;
	times = 0;
}

void bfs(){
	q[tail].left = 0; q[tail].right = 0; q[tail].father = -1;
	tail += 1;
	vis[0][0] = 1;
	while(head < tail){
		if(q[head].left == c || q[head].right == c){
			print(q[head]);
			return;
		}
		if(q[head].left != a){
			q[tail].left = a;
			q[tail].right = q[head].right;
			if(!vis[q[tail].left][q[tail].right]){
				vis[q[tail].left][q[tail].right] = 1;
				q[tail].father = head;
				q[tail].ope = 1;
				tail += 1;
			}
		}
		if(q[head].right != b){
			q[tail].left = q[head].left;
			q[tail].right = b;
			if(!vis[q[tail].left][q[tail].right]){
				vis[q[tail].left][q[tail].right] = 1;
				q[tail].father = head;
				q[tail].ope = 2;
				tail += 1;
			}
		}
		if(q[head].right != b){
			int need = b - q[head].right;
			if(q[head].left < need){
				q[tail].left = 0;
				q[tail].right = q[head].right + q[head].left;
				if(!vis[q[tail].left][q[tail].right]){
					vis[q[tail].left][q[tail].right] = 1;
					q[tail].father = head;
					q[tail].ope = 3;
					tail += 1;
				}
			}
			else{
				q[tail].left = q[head].left - need;
				q[tail].right = b;
				if(!vis[q[tail].left][q[tail].right]){
					vis[q[tail].left][q[tail].right] = 1;
					q[tail].father = head;
					q[tail].ope = 3;
					tail += 1;
				}
			}
		}
		if(q[head].left != a){
			int need = a - q[head].left;
			if(q[head].right < need){
				q[tail].right = 0;
				q[tail].left = q[head].left + q[head].right;
				if(!vis[q[tail].left][q[tail].right]){
					vis[q[tail].left][q[tail].right] = 1;
					q[tail].father = head;
					q[tail].ope = 4;
					tail += 1;
				}
			}
			else{
				q[tail].left = a;
				q[tail].right = q[head].right - need;
				if(!vis[q[tail].left][q[tail].right]){
					vis[q[tail].left][q[tail].right] = 1;
					q[tail].father = head;
					q[tail].ope = 4;
					tail += 1;
				}
			}
		}
		if(q[head].left != 0){
			q[tail].left = 0;
			q[tail].right = q[head].right;
			if(!vis[q[tail].left][q[tail].right]){
				vis[q[tail].left][q[tail].right] = 1;
				q[tail].father = head;
				q[tail].ope = 5;
				tail += 1;
			}
		}
		if(q[head].right != 0){
			q[tail].right = 0;
			q[tail].left = q[head].left;
			if(!vis[q[tail].left][q[tail].right]){
				vis[q[tail].left][q[tail].right] = 1;
				q[tail].father = head;
				q[tail].ope = 6;
				tail += 1;
			}
		}
		head += 1;
	}
	puts("impossible");
}

int main(){
	while(cin >> a >> b >> c){
		init();
		bfs();
	}
}

H - Oil Deposits

H - Oil Deposits

题意:
 在n*m的图中’@'表示该处藏有石油,如果这些蕴藏石油的小方格相邻(横向相邻,纵向相邻,还有对角相邻),那么它们被认为是同一油藏的一部分,问这些石油组成多少部分。

题解:
 裸bfs。

#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 222;
char s[maxn][maxn];
bool vis[maxn][maxn];
int step[maxn][maxn][maxn];
int num = 0;
int n,m,h;
int startX, startY, startZ, endX, endY, endZ;
//const int Move[6][3] = {{0,0,1},{0,0,-1},{0,1,0},{0,-1,0},{1,0,0},{-1,0,0}};
const int Move[8][2] = {{0,1},{0,-1},{-1,0},{1,0},{1,1},{1,-1},{-1,1},{-1,-1}};
int minn;

struct node{
	int x;
	int y;
	int num;
};

queue<node>q;
node st;
node End;

void init(){
	while(!q.empty()) q.pop();
	memset(vis,false,sizeof(vis));
}

inline bool check(int x, int y){
	if(x >= 0 && x < n && y >= 0 && y < m && !vis[x][y] && s[x][y] == '@') return true;
	return false;
}

void bfs(){
	node cur;
	cur.x = startX;
	cur.y = startY;
	q.push(cur);
	vis[cur.x][cur.y] = 1;
	while(!q.empty()){
		cur = q.front();
		q.pop();
		for(int i=0; i<8; ++i){
			int tx = cur.x + Move[i][0];
			int ty = cur.y + Move[i][1];
			if(check(tx,ty)){
				vis[tx][ty] = 1;
				node k;
				k.x = tx; k.y = ty;
				q.push(k);
			}
		}
	}
}


int main(){
	while(~scanf("%d%d",&n,&m)){
		if(m == 0) break;
		init();
		int sum = 0;
		for(int i=0; i<n; ++i){
			getchar();
			for(int j=0; j<m; ++j){
				scanf("%c",&s[i][j]);
			}
		}
		for(int i=0; i<n; ++i){
			for(int j=0; j<m; ++j){
				if(s[i][j] == '@' && !vis[i][j]){
					startX = i;
					startY = j;
					//cout << i << " " << j << endl;
					bfs();
					sum += 1;
				}
			}
		}
		cout << sum << endl;
	}
}

I - 非常可乐

I - 非常可乐

题意:
 有一杯可乐和两个杯子,询问最少的次数满足两个被子中的可乐平分。

题解:
 可乐体积为奇数显然不满足,然后bfs遍历所有情况即可。

#include 
#include 
#include 
using namespace std;

int n,m,s;
bool vis[109][109][109];

struct node{
    int left;
    int mid;
    int right;
    int step;
};

queue<node>q;
node cnt;

void init(){
    memset(vis,0,sizeof(vis));
    while(!q.empty()) q.pop();
}

void bfs(){
    //cout << n << endl;
    q.push(cnt);
    while(!q.empty()){
        node k = q.front();
        q.pop();
        //cout << k.left << " " << k.mid << " " << k.right << " " << k.step << endl;
        if((k.left == n && k.mid == n) || (k.left == n && k.right == n) || (k.mid == n && k.right == n)){
            cout << k.step << endl;
            //cout << k.left << " " << k.mid << " " << k.right << endl;
            return;
        }
        node new_k = k;
        if(k.left != 0){
            new_k.left -= (m - new_k.mid);
            new_k.mid = m;//1往2倒
            new_k.step += 1;
            if(!vis[new_k.left][new_k.mid][new_k.right])
            q.push(new_k);
            vis[new_k.left][new_k.mid][new_k.right] = 1;
        }
        new_k = k;
        if(k.left != 0){
            new_k.left -= (s - new_k.right);
            new_k.right = s;//1往3倒
            new_k.step += 1;
            if(!vis[new_k.left][new_k.mid][new_k.right])
            q.push(new_k);
            vis[new_k.left][new_k.mid][new_k.right] = 1;
        }
        new_k = k;
        if(k.mid != 0){
            new_k.mid = 0;
            new_k.left += k.mid;//2往1倒
            new_k.step += 1;
            if(!vis[new_k.left][new_k.mid][new_k.right])
            q.push(new_k);
            vis[new_k.left][new_k.mid][new_k.right] = 1;
        }
        new_k = k;
        if(k.mid != 0){
            if(k.mid < s - k.right) new_k.mid = 0, new_k.right += k.mid;
            else new_k.mid -= (s - k.right), new_k.right = s;
            new_k.step += 1;
            if(!vis[new_k.left][new_k.mid][new_k.right])
            q.push(new_k);
            vis[new_k.left][new_k.mid][new_k.right] = 1;
        }
        new_k = k;
        if(k.right != 0){
            new_k.left += k.right;
            new_k.right = 0;
            new_k.step += 1;
            if(!vis[new_k.left][new_k.mid][new_k.right])
            q.push(new_k);
            vis[new_k.left][new_k.mid][new_k.right] = 1;
        }
        new_k = k;
        if(k.right != 0){
            if(k.right < m - k.mid) new_k.mid += k.right, new_k.right = 0;
            else new_k.mid = m, new_k.right -= (m - k.mid);
            new_k.step += 1;
            if(!vis[new_k.left][new_k.mid][new_k.right])
            q.push(new_k);
            vis[new_k.left][new_k.mid][new_k.right] = 1;
        }
        //cout << q.size() << endl;
    }
    puts("NO");
}

int main(){
    while(~scanf("%d%d%d",&n,&m,&s)){
        if(n == 0) break;
        if(n % 2 != 0){
            puts("NO");
            continue;
        }
        init();
        cnt.left = n; cnt.mid = 0; cnt.right = 0;
        n /= 2;
        bfs();
    }
}

J - Find a way

J - Find a way

题意:
 两个人出发,有多个KFC,询问两个人到同一个KFC的最短路径。

题解:
 对两个点跑两次bfs,然后用两个二维数组记录两个人到每个KFC的距离,维护距离最小值即可。

AC_Code:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
int n,m;

bool vis[205][205];
char s[205][205];
int a[205][205];
int b[205][205];
const int Move[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};

struct node
{
	int x;
	int y;
	int step;
	node(){}
	node(int xx, int yy, int st){
		x = xx;
		y = yy;
		step = st;
	}
};

queue<node>q;
node p1,p2;

void init(){
	memset(vis,0,sizeof(vis));
	while(!q.empty()) q.pop();
}

void bfs1(node k){
	q.push(k);
	while(!q.empty()){
		node new_k = q.front();
		q.pop();
		for(int i=0; i<4; ++i){
			int tx = new_k.x + Move[i][0];
			int ty = new_k.y + Move[i][1];
			if(tx >= 0 && tx < n && ty >= 0 && ty < m && !vis[tx][ty] && s[tx][ty] != '#'){
				if(s[tx][ty] == '@'){
					a[tx][ty] = new_k.step + 1;
				}
				vis[tx][ty] = 1;
				node ppp = node(tx,ty,new_k.step+1);
				q.push(ppp);
			}
		}
 	}
}

void bfs2(node k){
	q.push(k);
	while(!q.empty()){
		node new_k = q.front();
		q.pop();
		for(int i=0; i<4; ++i){
			int tx = new_k.x + Move[i][0];
			int ty = new_k.y + Move[i][1];
			if(tx >= 0 && tx < n && ty >= 0 && ty < m && !vis[tx][ty] && s[tx][ty] != '#'){
				if(s[tx][ty] == '@'){
					b[tx][ty] = new_k.step + 1;
				}
				vis[tx][ty] = 1;
				node ppp = node(tx,ty,new_k.step+1);
				q.push(ppp);
			}
		}
 	}
}

int main(){
	while(~scanf("%d%d",&n,&m)){
		init();
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		for(int i=0; i<n; ++i){
			scanf("%s",s[i]);
		}
		for(int i=0; i<n; ++i){
			for(int j=0; j<m; ++j){
				if(s[i][j] == 'Y'){
					p1 = node(i,j,0);
					vis[i][j] = 1;
				}
				if(s[i][j] == 'M'){
					p2 = node(i,j,0);
					vis[i][j] = 1;
				}
			}
		}
		bfs1(p1);
		init();
		for(int i=0; i<n; ++i){
			for(int j=0; j<m; ++j){
				if(s[i][j] == 'Y'){
					p1 = node(i,j,0);
					vis[i][j] = 1;
				}
				if(s[i][j] == 'M'){
					p2 = node(i,j,0);
					vis[i][j] = 1;
				}
			}
		}
		bfs2(p2);
		int minn = 0x3f3f3f3f;
		for(int i=0; i<n; ++i){
			for(int j=0; j<m; ++j){
				if(s[i][j] == '@' && vis[i][j]){
					//cout << i << " " << j << " " << a[i][j] << " " << b[i][j] << endl;
					minn = min(minn, a[i][j] + b[i][j]);
				}
			}
		}
		cout << minn * 11 << endl;
	}
}

K - 马走日

K - 马走日

题意:
 给定n*m大小的棋盘,以及马的初始位置(x,y),要求不能重复经过棋盘上的同一个点,计算马可以有多少途径遍历棋盘上的所有点。

题解:
 裸dfs。

#include 
#include 
#include 
#include 
using namespace std;

int n,m;
int startX, startY;
int num;
bool vis[20][20];
int Move[9][2] = {{0,0},{-2,-1},{-2,1},{-1,-2},{-1,2},{1,-2},{1,2},{2,1},{2,-1}};

void init(){
	num = 0;
	memset(vis,false,sizeof(vis));
}

bool kiss(int x, int y){
	if(x >= 0 && x < n && y >= 0 && y < m && !vis[x][y]) return true;
	return false;
}

void dfs(int x, int y, int step){
	if(step == n * m){
		num++;
		return;
	}
	for(int i=0; i<9; ++i){
		int tx = x + Move[i][0];
		int ty = y + Move[i][1];
		if(kiss(tx,ty)){
			vis[tx][ty] = true;
			dfs(tx,ty,step+1);
			vis[tx][ty] = false;
		}
	}
}

int main(){
	int t;
	while(~scanf("%d",&t)){
		while(t--){
			init();
			scanf("%d%d%d%d",&n,&m,&startX,&startY);
			vis[startX][startY] = true;
			dfs(startX,startY,1);
			printf("%d\n",num);
		}
	}
}

L - 海贼王之伟大航路

L - 海贼王之伟大航路

没思路,待补。

M - 迷宫问题

M - 迷宫问题

题意:
 输出一个二维迷宫从左上角到右下角最短路径。

题解:
 由于要输出路径,因此不能用queue 弹出,手写队列(由于数据小,不会出现爆栈情况)记录路径。

AC_Code:

//
//Write by Yuan Xilan on 2019...
//
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SZ(X) ((int)(X).size())
#define ALL(X) (X).begin(), (X).end()
#define REP(I, N) for (int I = 0; I < (N); ++I)
#define REPP(I, A, B) for (int I = (A); I < (B); ++I)
#define FOR(I, A, B) for (int I = (A); I <= (B); ++I)
#define FORS(I, S) for (int I = 0; S[I]; ++I)
#define RS(X) scanf("%s", (X))
#define SORT_UNIQUE(c) (sort(c.begin(),c.end()), c.resize(distance(c.begin(),unique(c.begin(),c.end()))))
#define GET_POS(c,x) (lower_bound(c.begin(),c.end(),x)-c.begin())
#define CASET int ___T; scanf("%d", &___T); for(int cs=1;cs<=___T;cs++)
#define MP make_pair
#define PB push_back
#define MS0(X) memset((X), 0, sizeof((X)))
#define MS1(X) memset((X), -1, sizeof((X)))
#define LEN(X) strlen(X)
#define F first
#define S second
using namespace std;
typedef long long ll,LL;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef vector<LL> VL;
typedef vector<PII> VPII;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;
void R() {}
#ifdef HOME
 #define DEBUG(...) {printf("# ");printf(__VA_ARGS__);puts("");}
#else
 #define DEBUG(...)
#endif
const int maxn = 10;
ll a[maxn],b[maxn];
int mod = 1e9+7;
int n,m,num;
struct node{
	int x;
	int y;
	int father;
};
node q[20000];
char s[maxn][maxn];
int startX, startY;
const int Move[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
bool vis[maxn][maxn];
int fath[100100];

void print(int x){
	if(q[x].father != -1){
		print(q[x].father);
	}
	printf("(%d, %d)\n",q[x].x,q[x].y);
}

void bfs(){
	int head = 0, tail = 0;
	q[tail].x = 0; q[tail].y = 0; q[tail].father = -1;
	vis[0][0] = 1;
	tail += 1;
	while(head < tail){
		bool flag = false;
		for(int i=0; i<4; ++i){
			int tx = q[head].x + Move[i][0];
			int ty = q[head].y + Move[i][1];
			if(tx >= 0 && tx < 5 && ty >= 0 && ty < 5 && !vis[tx][ty] && s[tx][ty] == '0'){
				q[tail].x = tx; q[tail].y = ty; q[tail].father = head;
				vis[tx][ty] += 1;
				tail += 1;
			}
			if(tx == 4 && ty == 4){
				tail -= 1;
				print(tail);
			}
		}
		head += 1;
	}
}

int main(){
	for(int i=0; i<5; ++i){
		for(int j=0; j<5; ++j){
			scanf("%s",&s[i][j]);
		}
		getchar();
	}
	bfs();
}

N - 鸣人和佐助

N - 鸣人和佐助

题意:
 鸣人可以往上下左右四个方向移动,每移动一个距离需要花费1个单位时间,打败大蛇丸的手下不需要时间。鸣人有一定数量的查克拉,每一个单位的查克拉可以打败一个大蛇丸的手下。如果鸣人查克拉消耗完了,则只可以走到没有大蛇丸手下的位置,不可以再移动到有大蛇丸手下的位置。佐助在此期间不移动,大蛇丸的手下也不移动。请问,鸣人要追上佐助最少需要花费多少时间?

题解:
 单独跑bfs找到的路径不一定是时间最短的路径,因此使用优先队列,考虑每个队列中鸣人的时间和所需的查克拉,如果时间相等,则优先跑查克拉小的点,否则跑时间小的点,当所需查克拉大于手里有的查克拉时退出。

AC_Code:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 222;
char s[maxn][maxn];
bool vis[maxn][maxn];
int num = 0;
int n,m,h;
int startX, startY, startZ, endX, endY, endZ;
//const int Move[6][3] = {{0,0,1},{0,0,-1},{0,1,0},{0,-1,0},{1,0,0},{-1,0,0}};
const int Move[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
int minn;

struct node{
	int x;
	int y;
	int num;
	int step;
	
	friend bool operator <(const node A, const node B){
		if(A.step == B.step) return A.num > B.num;
		return A.step > B.step;
	}
	
	/*
	bool operator < (const node &a) const //按照查克拉最小值优先 结构体优先队列 
	{
		if(a.step==step)
		{
			return a.num
};

priority_queue<node>q;
node st;
node End;

void init(){
	while(!q.empty()) q.pop();
	memset(vis,false,sizeof(vis));
}

inline bool check(int x, int y){
	if(x >= 0 && x < n && y >= 0 && y < m && !vis[x][y]) return true;
	return false;
}

void bfs(){
	node cur;
	q.push(st);
	while(!q.empty()){
		cur = q.top();
		q.pop();
		//cout << cur.num << endl;
		if(cur.num > h) continue;
		for(int i=0; i<4; ++i){
			int tx = cur.x + Move[i][0];
			int ty = cur.y + Move[i][1];
			if(tx == End.x && ty == End.y){
				printf("%d\n",cur.step + 1);
				return;
			}
			if(check(tx,ty)){
				node k;
				//cout << tx << " " << ty << endl;
				k.x = tx; k.y = ty; k.step = cur.step + 1;
				if(s[tx][ty] == '#') k.num = cur.num + 1;
				else k.num = cur.num;
				vis[tx][ty] = 1;
				q.push(k);
			}
		}
	}
	printf("-1\n");
}


int main(){
	int t;
	int ans = 1;
	scanf("%d%d%d",&n,&m,&h);
		for(int i=0; i<n; ++i){
			getchar();
			for(int j=0; j<m; ++j){
				scanf("%c",&s[i][j]);
			}
		}
		
		for(int i=0; i<n; ++i){
			for(int j=0; j<m; ++j){
				if(s[i][j] == '@'){
					startX = i;
					startY = j;
				}
				if(s[i][j] == '+'){
					End.x = i; End.y = j;
				}
			}
		}
		st.x = startX; st.y = startY; st.num = 0; st.step = 0;
		vis[startX][startY] = 1;
		bfs();
}

O - 红与黑

O - 红与黑

题意:
 一个人从起点‘@’出发,问他可以到多少个’.’,此人不能通过’#’.

题解:
 裸dfs。

//
//Write by Yuan Xilan on 2019...
//
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SZ(X) ((int)(X).size())
#define ALL(X) (X).begin(), (X).end()
#define REP(I, N) for (int I = 0; I < (N); ++I)
#define REPP(I, A, B) for (int I = (A); I < (B); ++I)
#define FOR(I, A, B) for (int I = (A); I <= (B); ++I)
#define FORS(I, S) for (int I = 0; S[I]; ++I)
#define RS(X) scanf("%s", (X))
#define SORT_UNIQUE(c) (sort(c.begin(),c.end()), c.resize(distance(c.begin(),unique(c.begin(),c.end()))))
#define GET_POS(c,x) (lower_bound(c.begin(),c.end(),x)-c.begin())
#define CASET int ___T; scanf("%d", &___T); for(int cs=1;cs<=___T;cs++)
#define MP make_pair
#define PB push_back
#define MS0(X) memset((X), 0, sizeof((X)))
#define MS1(X) memset((X), -1, sizeof((X)))
#define LEN(X) strlen(X)
#define F first
#define S second
using namespace std;
typedef long long ll,LL;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef vector<LL> VL;
typedef vector<PII> VPII;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;
void R() {}
#ifdef HOME
 #define DEBUG(...) {printf("# ");printf(__VA_ARGS__);puts("");}
#else
 #define DEBUG(...)
#endif
const int maxn = 30;
ll a[maxn],b[maxn];
int mod = 1e9+7;
int n,m,num;
struct node{
	ll s1;	
};
node c;
queue<node>q;
char s[maxn][maxn];
int startX, startY;
const int Move[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
bool vis[maxn][maxn];

void dfs(int x, int y, int step){
	num++;
	for(int i=0; i<4; ++i){
		int tx = x + Move[i][0];
		int ty = y + Move[i][1];
		if(tx >= 0 && tx < n && ty >= 0 && ty < m && !vis[tx][ty] && s[tx][ty] == '.'){
			vis[tx][ty] = 1;
			dfs(tx,ty,step+1);
		}
	}
}

int main(){
	while(~scanf("%d%d",&m,&n) && m && n){
		num = 0;
		memset(vis,false,sizeof(vis));
		for(int i=0; i<n; ++i){
			scanf("%s",s[i]);
		}
		for(int i=0; i<n; ++i){
			for(int j=0; j<m; ++j){
				if(s[i][j] == '@'){
					startX = i;
					startY = j;
					break;
				}
			}
		}
		vis[startX][startY] = 1;
		dfs(startX, startY, 1);
		cout << num << endl;
	}
	
}

P - 棋盘问题

P - 棋盘问题

题意:
 在一个给定形状的棋,要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,求摆放k个棋子的所有可行的摆放方案C。

题解:
 从上往下遍历每个’#’,由于不能放在同一行,因此接下来的棋子应该往该行下面放,这样便能枚举所有的情况。

AC_Code:

#include 
using namespace std;

char s[10][10];
bool vis[10];
int n,k,num;

void init(){
    num = 0;
    memset(vis,0,sizeof(vis));
}

void dfs(int x, int y, int sum){
    if(sum == k){
        num += 1;
        return;
    }
    for(int i=x+1; i<n; ++i){
        for(int j=0; j<n; ++j){
            if(s[i][j] == '#' && !vis[j]){
                vis[j] = 1;
                dfs(i,j,sum+1);
                vis[j] = 0;
            }
        }
    }
}

int main(){
    while(~scanf("%d%d",&n,&k)){
        if(n == -1) break;
        init();
        for(int i=0; i<n; ++i){
            scanf("%s",s[i]);
        }
        dfs(-1,-1,0);
        cout << num << endl;
    }
}

Q - 拯救行动

Q - 拯救行动

题意:
 骑士可以向上、下、左、右四个方向移动,每移动一个位置需要1个单位时间,杀死一个守卫需要花费额外的1个单位时间。计算拯救行动成功需要花费最短时间。

 由于直接裸bfs找到的路径并不一定是花费时间最少的路径,因此采用优先队列处理,重载重新根据每个点所需的时间进行排序,然后bfs即可。

#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 222;
char s[maxn][maxn];
bool vis[maxn][maxn];
int step[maxn][maxn][maxn];
int num = 0;
int n,m,h;
int startX, startY, startZ, endX, endY, endZ;
//const int Move[6][3] = {{0,0,1},{0,0,-1},{0,1,0},{0,-1,0},{1,0,0},{-1,0,0}};
const int Move[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
int minn;

struct node{
	int x;
	int y;
	int num;
	friend bool operator <(const node A,const node B){
		return A.num > B.num;
	}
};

priority_queue<node>q;
node st;
node End;

void init(){
	while(!q.empty()) q.pop();
	memset(vis,false,sizeof(vis));
	st.x = 0; st.y = 0;  st.num = 0;
	End.x = 0; End.y = 0;  End.num = 0;
}

inline bool check(int x, int y){
	if(x >= 0 && x < n && y >= 0 && y < m && !vis[x][y] && s[x][y] != '#') return true;
	return false;
}

void bfs(){
	node cur;
	q.push(st);
	vis[st.x][st.y] = 1;
	int minn = 0x3f3f3f3f;
	while(!q.empty()){
		cur = q.top();
		q.pop();
		for(int i=0; i<4; ++i){
			int tx = cur.x + Move[i][0];
			int ty = cur.y + Move[i][1];
			if(s[tx][ty] == 'a'){
				minn = min(minn, cur.num+1);
				//cout << cur.num + 1 << endl;
				//return;
			}
			if(check(tx,ty)){
				vis[tx][ty] = 1;
				node k;
				k.x = tx; k.y = ty; k.num = cur.num;
				if(s[tx][ty] == '@') k.num += 1;
				else if(s[tx][ty] == 'x') k.num += 2;
				q.push(k);
			}
		}
	}
	if(minn == 0x3f3f3f3f) 
		printf("Impossible\n");
	else cout << minn << endl;
}


int main(){
	int t;
	while(~scanf("%d",&t)){
		while(t--){
			init();
			scanf("%d%d",&n,&m);
			for(int i=0; i<n; ++i){
				getchar();
				for(int j=0; j<m; ++j){
					scanf("%c",&s[i][j]);
					if(s[i][j] == 'r'){
						startX = i;
						startY = j;
					}
					if(s[i][j] == 'a'){
						endX = i;
						endY = j;
					}
				}
			}
			st.x = startX; st.y = startY; st.num = 0;
			bfs();
		}
	}
}

/*
2 5
@@@@@
rxxxa
*/

R - Saving Tang Monk

R - Saving Tang Monk

题意:
 要从K走到T处,并且要先收集k把钥匙,收集钥匙顺序递增,即拿到第一把钥匙才能拿到第二把钥匙,还有不超过五条蛇‘S’(之前没看到这里只有五条不会做),每次打蛇要+1s,蛇死了再路过是不用打的。

题意:
 只有五条蛇,给蛇编号然后状压记录打的蛇的状态。剩下的就BFS。(还不是很理解)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
int n,m;

bool vis[205][205][10];
char s[205][205];
char mp[205][205];
const int Move[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};

struct node
{
	int x;
	int y;
	int step;
	int key;
	int snake;
	node(){}
	node(int new_x, int new_y, int new_step, int new_key, int new_snake){
		x = new_x;
		y = new_y;
		step = new_step;
		key = new_key;
		snake = new_snake;
	}
	friend bool operator < (const node P, const node Q){
		return P.step > Q.step;
	}
};

priority_queue<node>q;
node Start;
node End;
int ans = 1;

void init(){
	while(!q.empty()) q.pop();
	memset(vis,0,sizeof(vis));
}

bool judge(int x, int y){
	if(x >= 0 && x < n && y >= 0 && y < n && s[x][y] != '#') return true;
	return false;
}

bool judge_s(node p, int x){
	if(p.snake & (1 << x)) return false;
	return true;
}

void bfs(){
	q.push(Start);
	vis[Start.x][Start.y][0] = 1;
	while(!q.empty()){
		node k = q.top();
		q.pop();
		for(int i=0; i<4; ++i){
			int tx = k.x + Move[i][0];
			int ty = k.y + Move[i][1];
			//cout << tx << " " << ty << " " << k.step << " " << k.cnt << endl;
			if(judge(tx,ty) && !vis[tx][ty][k.key]){
				//cout << tx << " " << ty << " " << k.step << " " << k.cnt << endl;
				if(k.key == m && s[tx][ty] == 'T'){
					cout << k.step + 1 << endl;
					return;
				}
				else if(s[tx][ty] == k.key + '0' + 1){//拿到钥匙
					vis[tx][ty][k.key] = 1;
					node new_k = node(tx,ty,k.step+1,k.key+1,k.snake);
					q.push(new_k);
				}
				else if(s[tx][ty] >= 0 && s[tx][ty] <= 5 && judge_s(k,s[tx][ty])){//遇到蛇
					vis[tx][ty][k.key] = 1;
					node new_k = node(tx,ty,k.step+2,k.key,k.snake|(1<<s[tx][ty]));
					q.push(new_k);
				}
				else{
					vis[tx][ty][k.key] = 1;
					node new_k = node(tx,ty,k.step+1,k.key,k.snake);
					q.push(new_k);
				}
			}
		}
	}
	printf("impossible\n");
}

int main(){
	while(~scanf("%d%d",&n,&m)){
		init();
		if(n == 0) break;
		for(int i=0; i<n; ++i){
			scanf("%s",s[i]);
		}
		int cnt = 0;
		for(int i=0; i<n; ++i){
			for(int j=0; j<n; ++j){
				if(s[i][j] == 'K'){
					Start = node(i,j,0,0,0);
					//vis[i][j] = 1;
				}
				if(s[i][j] == 'T'){
					End = node(i,j,0,m,0);
				}
				if(s[i][j] == 'S'){
					s[i][j] = cnt++;
				}
			}
		}
		bfs();
	}
}

S - Fire Game

S - Fire Game

题意:
 两个熊孩子在n*m的平地上放火玩,#表示草,两个熊孩子分别选一个#格子点火,火可以向上向下向左向右在有草的格子蔓延,点火的地方时间为0,蔓延至下一格的时间依次加一。求烧完所有的草需要的最少时间。如不能烧完输出-1。(两个火同时点)

题解:

AC_Code:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define MST(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int MAXN = 15;
const int INF = 0x3f3f3f3f;
char mp[MAXN][MAXN];
bool vis[MAXN][MAXN];
int dir[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
struct node {
	int x, y, cnt;
	node(int _x, int _y, int _c) {
		x = _x;
		y = _y;
		cnt = _c;
	}
	node() {}
} ;
vector <node> grass;
int n, m, t, res;
void init() {
	res = INF;
	grass.clear();
	MST(mp, 0);
}
void bfs(node s1, node s2) {
	MST(vis, false);
	queue <node> q;
	q.push(s1);
	q.push(s2);
	vis[s1.x][s1.y] = vis[s2.x][s2.y] = true;
	node now, next;
	int sum = 0;
	while (!q.empty()) {
		now = q.front();
		q.pop();
		if (mp[now.x][now.y] == '#') sum++;
//        cout << now.x << " " << now.y << " " << now.cnt << " " << sum << endl;
		if (sum == grass.size()) {
			res = min(res, now.cnt);
		}
		for (int i = 0; i < 4; i++) {
			next.x = now.x + dir[i][1];
			next.y = now.y + dir[i][0];
			next.cnt = now.cnt + 1;
			if (next.x < 0 || next.y < 0 || next.x >= n || next.y >= m) continue;
			if (vis[next.x][next.y] || mp[next.x][next.y] == '.') continue;
			vis[next.x][next.y] = true;
			q.push(next);
		}
	}
}
int main() {
	ios::sync_with_stdio(false);
	cin >> t;
	for (int tt = 1; tt <= t; tt++) {
		init();
		cin >> n >> m;
		for (int i = 0; i < n; i++)
			for (int j = 0; j < m; j++) {
				cin >> mp[i][j];
				if (mp[i][j] == '#') {
					node tmpnd;
					tmpnd.x = i;
					tmpnd.y = j;
					tmpnd.cnt = 0;
					grass.push_back(tmpnd);
				}
			}
//        cout << grass.size() << endl;
		for (int i = 0; i < grass.size(); i++)
			for (int j = i; j < grass.size(); j++)
				bfs(grass[i], grass[j]);
		cout << "Case " << tt << ": ";
		if (res != INF) cout << res << endl;
		else cout << "-1" << endl;
	}
}

T - Fire!

T - Fire!

题意:
 一个人从J出发,同时火从F处开始燃烧,每1s火往上下左右扩散,人可以往上下左右移动一格,‘#’表示墙壁,逃离边界即可避免火灾,询问是否可以安全逃离。(PS:本题坑:F不止一处,也可能没F(数据并无体现。。。))

题解:
 特判没有火的情况(裸bfs),然后考虑有火的情况,每一秒先处理火先烧的区域,vis数组标记,然后人再移动,bfs即可。

AC_Code:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 1222;
string s[maxn];
bool vis[maxn][maxn];
int num = 0;
int n,m,h;
int startX, startY, startZ, endX, endY, endZ;
//const int Move[6][3] = {{0,0,1},{0,0,-1},{0,1,0},{0,-1,0},{1,0,0},{-1,0,0}};
const int Move[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
int minn;

struct node{
	int x;
	int y;
	int num;
};

queue<node>q;
queue<node>new_q;
queue<node>f;
queue<node>new_f;
node st;
node End;

void init(){
	while(!q.empty()) q.pop();
	while(!f.empty()) f.pop();
	while(!new_f.empty()) new_f.pop();
	while(!new_q.empty()) new_q.pop();
	memset(vis,false,sizeof(vis));
}

inline bool check(int x, int y){
	if(x >= 0 && x < n && y >= 0 && y < m && !vis[x][y] && s[x][y] != '#') return true;
	return false;
}

void bfs(){
	node cur;
	node fire;
	q.push(st);
	//cout << q.empty() << " " << f.size() << endl;为空返回1
	
	if(f.size() == 0){
		while(!q.empty()){
			node test = q.front();
			q.pop();
			for(int i=0; i<4; ++i){
				int tx = test.x + Move[i][0];
				int ty = test.y + Move[i][1];
				if(tx < 0 || tx >= n || ty < 0 || ty >= m){
					cout << test.num + 1 << endl;
					return;
				}
				if(!vis[tx][ty] && s[tx][ty] != '#'){
					vis[tx][ty] = 1;
					node k;
					k.x = tx; k.y = ty; k.num = test.num + 1;
					q.push(k);
				}
			}
		}
	}

	while(!q.empty() || !f.empty()){

		//cout << f.size() << endl;
		while(!f.empty()){
			fire = f.front();
			f.pop();
			for(int i=0; i<4; ++i){
				int tx = fire.x + Move[i][0];
				int ty = fire.y + Move[i][1];
				if(check(tx,ty)){
					vis[tx][ty] = 1;
					node k;
					k.x = tx; k.y = ty; k.num = 0;
					//cout << k.x << " " << k.y << endl;
					new_f.push(k);
				}
			}
		}
		while(!new_f.empty()){
			f.push(new_f.front());
			new_f.pop();
		}
		
		while(!q.empty()){
			cur = q.front();
			q.pop();
			for(int i=0; i<4; ++i){
				int tx = cur.x + Move[i][0];
				int ty = cur.y + Move[i][1];
				if(tx < 0 || tx >= n || ty < 0 || ty >= m){
					//cout << cur.x << " " << cur.y << " " << cur.num << endl;
					cout << cur.num + 1 << endl;
					return;
				}
				if(!vis[tx][ty] && s[tx][ty] != '#'){
					vis[tx][ty] = 1;
					node k;
					k.x = tx; k.y = ty; k.num = cur.num + 1;
					//cout << k.x << " " << k.y << " " << k.num << endl;
					new_q.push(k);
				}
			}
		}
		while(!new_q.empty()){
			q.push(new_q.front());
			new_q.pop();
		}
	}
	printf("IMPOSSIBLE\n");
}


int main(){
	int t;
	int ans = 1;
	
		cin >> n >> m;
		init();
		for(int i=0; i<n; ++i){
			cin >> s[i];
		}
		for(int i=0; i<n; ++i){
			for(int j=0; j<m; ++j){
				if(s[i][j] == 'J'){
					startX = i;
					startY = j;
				}
				if(s[i][j] == 'F'){
					End.x = i; End.y = j;
					vis[i][j] = 1;
					f.push(End);
				}
			}
		}
		st.x = startX; st.y = startY; st.num = 0;
		vis[startX][startY] = 1;
		bfs();
	
}
/*
4 4
####
FJ..
...F
#...
*/
/*
4 5
FF#..
#...#
#.J.#
###.F
*/
/*
5 5
#####
#...#
#.#.#
#J#.#
###.#
*/
/*
6 4
####
#F.#
#.J#
#..#
#.#.
#...
*/////

U - Cops and Robbers

U - Cops and Robbers

题意:
 一帮盗贼从‘B’处出发,为了不让盗贼逃走,需建立围墙进行防卫,小写字母表示可以建立围墙,最后一行的输入表示对应的字母处建立围墙的金钱,’.'处盗贼可以通过但是不能建立围墙,询问最少需要多少金钱可防止盗贼逃走。

题解:
(待补)

你可能感兴趣的:([kuangbin带你飞]专题一 简单搜索(大全))