Loading

P1312 [NOIP2011 提高组] Mayan 游戏

题面

一起来打块。。。。dnm,调了一晚上==

知识点:模拟,搜索

操作:掉块,消块,移块,判最终是否合法。

掉块:注意有空块的时候才掉,对于每一列从下往上扫一遍就好。

消块:有连续三块才能消,但不是一遇到三块能消,这样如果有连续的五块,剩两块就没法消了,所以对能消的块先打个标记,最后一起消了就好了。注意:如果能消,肯定要执行一次掉块操作,执行完掉块还要进行消块,因为掉块可能会导致重新组合成可以新的可以消的块,直到不能消了位置,用一个循环实现就好。

移块:\(dfs\)​​ 枚举每一步移动哪一个块,记录移动之前的状态方便回溯,过程中把答案记下就好了。

移块时剪枝:一个块向左移,要保证左边没有快,如果向右移要保证右边有不同颜色的块。

判最终是否合法:看最下面一行是否为空就好了。

code

/*
work by:Ariel_
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#define ll long long
#define rg register
using namespace std;
int read(){
    int x = 0,f = 1; char c = getchar();
    while(c < '0'||c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') {x = x*10 + c - '0'; c = getchar();}
    return x*f;
}
struct Ans{
   int x, y, d;
}ans[6];
int n, k, mp[6][8], fag, last[6][6][8], Step;//mp[i][j]: x = i, y = j; 起始从(1, 1)开始,按照数学坐标系模拟
bool res[6][8];
void down() {//掉落 
   for (int i = 1; i <= 5; i++) {
     int x = 0;
   	 for (int j = 1; j <= 7; j++) {
   	      if (!mp[i][j]) x++;
		  else {
		  	if (x == 0) continue; 
		  	mp[i][j - x] = mp[i][j], mp[i][j] = 0;
		  }
	   }
   }
}
bool delet() {//消除操作 
   int flag = 0; 
   for (int i = 1; i <= 5; i++) {
   	  for (int j = 1; j <= 7; j++) {
   	  	   if (i - 1 >= 1 && i + 1 <= 5 && mp[i - 1][j] == mp[i][j] && mp[i + 1][j] == mp[i][j] && mp[i][j]) {
   	  	   	    res[i - 1][j] = 1, res[i][j] = 1, res[i + 1][j] = 1, flag = 1;
			}
		   if(j - 1 >= 1 && j + 1 <= 7 && mp[i][j - 1] == mp[i][j] && mp[i][j] == mp[i][j + 1] && mp[i][j]) {
		   	    res[i][j] = 1, res[i][j - 1] = 1, res[i][j + 1] = 1, flag = 1;
		   }
		}
   }
   if (flag == 0) return false; 
   for (int i = 1; i <= 5; i++) {
   	  for (int j = 1; j <= 7; j++) {
   	  	   if (res[i][j]) mp[i][j] = 0, res[i][j] = 0;
		}
   }
   return true; 
}
void move(int x, int y, int d) {
   swap(mp[x][y], mp[x + d][y]);
   down();
   while(delet()) down();//连续消 
} 
bool check() {
   for (int i = 1; i <= 5; i++) if (mp[i][1]) return 0;
   return 1;
} 
void copy(int x) {
   for (int i = 1; i <= 5; i++) {
   	  for (int j = 1; j <= 7; j++) {
   	  	   last[x][i][j] = mp[i][j];   
		}
   }
}
void dfs(int step) {
  if (check()) {
  	 for (int i = 1; i <= n; i++) {
  	    printf("%d %d %d\n", ans[i].x, ans[i].y, ans[i].d);	 
	 }
	 exit(0);
  }
  if (step == n + 1) return ;//超步数
  copy(step);
  for (int i = 1; i <= 5; i++) {
  	 for (int j = 1; j <= 7; j++) {
  	   if (mp[i][j]) {
  	   	   if (i + 1 <= 5 && mp[i][j] != mp[i + 1][j]){//右侧没有方块 
  	   	       move(i, j, 1);
			   ans[step].x = i - 1, ans[step].y = j - 1, ans[step].d = 1;
               dfs(step + 1);
			   for (int i = 1; i <= 5; i++) {
			   	 for (int j = 1; j <= 7; j++) {
			   	 	    mp[i][j] = last[step][i][j];
					}
			   }
			   ans[step].x = -1, ans[step].y = -1, ans[step].d = -1;	
			}
		   if (i - 1 >= 1 && mp[i - 1][j] == 0) {
		   	   move(i, j, -1);
		   	   ans[step].x = i - 1, ans[step].y = j - 1, ans[step].d = -1;
		   	   dfs(step + 1);
		   	   for (int i = 1; i <= 5; i++) {
		   	   	  for (int j = 1; j <= 7; j++) {
		   	   	  	   mp[i][j] = last[step][i][j];
				    }
				}
			   ans[step].x = -1, ans[step].y = -1, ans[step].d = -1;
		   }
		}
	 }
  }
}
int main(){
   n = read();
   memset(ans, -1, sizeof ans);
   for (int i = 1, tot, x; i <= 5; i++) {
   	  x = read(), tot = 1;
   	  while(x) {mp[i][tot++] = x, x = read();}
   }

   dfs(1);
   puts("-1");
   return 0;
}
posted @ 2021-08-04 23:10  Dita  阅读(41)  评论(0编辑  收藏  举报