HDU 3500 Fling

\[\color{blue}{Fling} \]

\[\color{green}{Time\;Limit: 6000/3000 MS (Java/Others)\quad Memory\;Limit: 65535/65535 K (Java/Others)} \]


\(\color{CornflowerBlue}{Problem\;Description}\)

Fling is a kind of puzzle games available on phone.
This game is played on a board with \(7\) rows and \(8\) columns. Each puzzle consists of a set of furballs placed on the board. To solved a puzzle, you need to remove the furballs from board until there is no more than one furball on the board. You do this by 'flinging' furballs into other furballs, to knock them off the board. You can fling any furballs in four directions (up, left, right, down). The flung furball stops at the front grid of another one as soon as knocking it. And the knocked furball continues to rolling in the same direction until the last knocked one goes off the board. For instance, A furball at \((0, 0)\) rolls right to the furball at \((0, 5)\), then it will stop at \((0, 4)\). Moreover, the latter will roll to right. You cannot fling a furball into a neighbouring furball, the one next to in any of four directions. However, it is permitted for a rolling ball knocks into a ball with a neighbour in that direction.


\(\color{CornflowerBlue}{Input}\)

The input contains multiple test cases.
For each case, the \(7\) lines with \(8\) characters describe the board. '\(X\)' represents a empty grid and '\(O\)'' represents a grid with a furball in it. There are no more than \(12\) furballs in any board.
Each case separated by a blank line.


\(\color{CornflowerBlue}{Output}\)

For each case, print a line formatted as "\(CASE\#NUM:\)", where \(NUM\) is the number of current case.
Then every 'fling' prints a line. Each line contains two integers \(X, Y\) and a character \(Z\). The flung furball is located at grid \((X, Y)\), the top-left grid is \((0, 0)\). And \(Z\) represents the direction this furball towards: \(U\) (Up), \(L\) (Left), \(R\) (Right) and \(D\) (Down);
Print a blank line between two cases.
You can assume that every puzzle could be solved.
If there are multiple solve sequences, print the smallest one. That is, Two sequences \(A\;(A_1, A_2, A_3, ..., A_n)\) and \(B\;(B_1, B_2, B_3 ,..., B_n)\). Let \(k\) be the smallest number that \(A_k \ne B_k\).
Define \(A < B\) :
(1) \(X \in A_k < X \in B_k\);
(2) \(Y \in A_k < Y \in B_k \quad and \quad X \in A_k = X \in B_k\);
(3) \(Z \in A_k < Z \in B_k \quad and \quad (X,Y) \in A_k = (X,Y) \in B_k\);
The order of \(Z\): \(U < L < R < D\).


\(\color{CornflowerBlue}{Sample\;Input}\)

XXXXXXXX
XXOXXXXX
XXXXXXXX
XXXXXXXX
XOXXXXOX
XXXXXXXX
XXXXXXXX

XXXXXXXX
XOXOXOOX
XXXXXXXX
XXXXXXXX
XXXXXXXX
XXXXXXXX
XXXXXXXX

\(\color{CornflowerBlue}{Sample\;Output}\)

CASE #1:
4 6 L
1 2 D

CASE #2:
1 1 R
1 4 L
1 3 R

\(\color{CornflowerBlue}{Author}\)

EvilSeraph


\(\color{CornflowerBlue}{Source}\)

2010 ACM-ICPC Multi-University Training Contest(7)——Host by HIT


\(\color{CornflowerBlue}{Recommend}\)

zhouzeyong | We have carefully selected several similar problems for you: 3504 3506 3507 3501 3499




题目描述

Fling是一种可以在手机上玩的益智游戏。

这个游戏是在一个有\(7\)\(8\)列的棋盘上进行的。 每个谜题由放置在木板上的一些毛球组成。 为了解决谜题,你需要从木板上移除毛球,直到木板上只有一个毛球。 完成的方式是通过把毛球扔向其他毛球,把它们从木板上打下来。 你可以向四个方向(上、左、右、下)投掷任何毛球。 扔的毛球会停留在它撞到的另一个毛球的前面一格。 被打过的毛球继续向同样的方向滚动,直到最后一个被撞过的毛球从木板上掉下来。 例如,在\((0,0)\)处的毛球向右朝在\((0,5)\)处的毛球滚动,然后它将在\((0,4)\)处停止。 此外,后者将向右滚动。 你不能把一个毛球扔向一个在四个方向的任何一个旁边相邻的毛球。 然而,允许滚动的毛球在这个方向上与邻居一起敲击毛球。



输入

输入包含多个测试样例。
对于每组样例,\(7\)\(8\)个字符描述木板。'X' 表示一个空格,'O'表示一个有毛球的格。 任何一块木板上的毛球不超过12个。
每隔一组空一行。



输出

对于每个样例,打印一条格式为“\(CASE\#NUM:\)”的行,其中\(NUM\)是当前案例的数量。
然后每个'fling'都打印一行。 每行包含两个整数\(X,Y\)和一个字符\(Z\)。 可扔的毛球位于网格\((X,Y)\),左上角网格为\((0,0)\)。 而\(Z\)代表了这个毛球扔的方向:\(U\)(向上),\(L\)(左),\(R\)(右)和\(D\)(向下);
在两个组之间打印一条空行。
你可以假设每个谜题都可以解决。
如果有多个解序列,则打印最小的一个。 也就是说,两个序列\(A(A_1、A_2、A_3、...、A_n)\)\(B(B_1、B_2、B_3、...、B_n)\)。 设\(k\)\(A_k\ne B_k\)的最小数。
定义\(A<B\)
(1) \(X \in A_k < X \in B_k\);
(2) \(Y \in A_k < Y \in B_k \quad 和 \quad X \in A_k = X \in B_k\);
(3) \(Z \in A_k < Z \in B_k \quad 和 \quad (X,Y) \in A_k = (X,Y) \in B_k\);
\(Z\)的顺序:\(U < L < R < D\).



Solution

思路借鉴于猪突猛进!!! 的hdu 3500 还是搜索

1.题意本身很明确,但搜索过程的回溯却没有那么简单;

2.因为毛球可能接力撞击,导致整个图发生巨大变化,所以需要维护好扔毛球前的所有相关毛球的位置信息,以便于回溯(这也是本题相较于HDU 2821 Pusher 更难的原因)

3.细节见代码

  • TAG:搜索;回溯



std.cpp

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<deque>
using namespace std;
typedef struct Node{
	int x,y;
	char z;
	Node(){}
	Node(int _x,int _y,char _z) :x(_x),y(_y),z(_z){};
}Node;
deque<Node>ansdeq;
int CASE,furball;
int fx[]={-1,0,0,1};
int fy[]={0,-1,1,0};
char board[10][10],Z[]={'U','L','R','D'};
bool moveflag,flag;
bool in_Board(int x,int y){ return 0<=x&&x<7&&0<=y&&y<8; }
void dfs(int rest_furball){
	if(rest_furball==1){ flag=1; return; }
	for(int x=0;x<7;++x)
		for(int y=0;y<8;++y)
            //因为每次操作要改变多个毛球的位置情况,为了保证输出答案字典序最小,需要重新遍历整个地图
			if(board[x][y]=='O'){
				moveflag=0;
				//moveflag代表了本次扔毛球是否合法
				for(int i=0;i<4;++i){
					int nx=x+fx[i],ny=y+fy[i];
					
					if(!in_Board(nx,ny)||board[nx][ny]=='O') continue;
					//如果旁边的位置出界或者存在其他毛球,则不能扔毛球
					//Q:旁边的位置出界为何不能直接把它扔出去?
					//A:因为这一操作不符合题意,不能将毛球直接扔下去,一定是被撞的毛球被扔下去
					while(in_Board(nx,ny)){
						nx+=fx[i],ny+=fy[i];
						
						if(board[nx][ny]=='O'){
							moveflag=1;
							board[nx][ny]='X';
							board[nx-fx[i]][ny-fy[i]]='O';
						}
                        //对于这几行代码,需要细细品味,假设当前情况为XOXOOOX
                        //将(0,1)的毛球往右扔,那么第一次状态会变化为XXOXOOX
                        //继续循环,就可以发现,第二次状态的变化会变为XXOOXOX
                        //继续循环,就会发现,最终的状态的变化会停留在XXOOOXX
                        //这样,就可以完成连环碰撞的效果
					}
					
					if(moveflag){
						board[x][y]='X';
						ansdeq.push_back(Node(x,y,Z[i]));
						//将最初扔毛球的位置清除,记录此次操作
                        
						dfs(rest_furball-1);
						if(flag) return;
						//flag代表是否找到一种可行的方案,找到即可退出搜索
                        
                        //如下为回溯过程
						while(nx!=x||ny!=y){
							nx-=fx[i]; ny-=fy[i];
							if(board[nx][ny]=='O'){
								board[nx][ny]='X';
								board[nx+fx[i]][ny+fy[i]]='O';
							}
                            //和上面的循环同理,倒着往回退,也能完成连环碰撞还原的效果
						}
						board[x][y]='O';
						ansdeq.pop_back();
					}
				}
			}
}
int main(){
	while(scanf("%s",board[0])!=EOF){
		flag=furball=0;
		for(int i=1;i<7;++i) scanf("%s",board[i]);
		for(int i=0;i<7;++i)
			for(int j=0;j<8;++j)
				if(board[i][j]=='O') ++furball;
				
		dfs(furball);
		
		if(CASE>=1) putchar('\n');
		printf("CASE #%d:\n",++CASE);
		Node ans;
		while(!ansdeq.empty()){
			ans=ansdeq.front(); ansdeq.pop_front();
			printf("%d %d %c\n",ans.x,ans.y,ans.z);
		}
	}
	return 0;
}
posted @ 2021-01-08 20:37  PotremZ  阅读(83)  评论(0编辑  收藏  举报