【hdu1175】連連看——dfs(剪枝)

題目:

連連看

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 27462    Accepted Submission(s): 6809


Problem Description
“連連看”相信很多人都玩過。沒玩過也沒關係,下面我給大家介紹一下遊戲規則:在一個棋盤中,放了很多的棋子。如果某兩個相同的棋子,可以通過一條線連起來(這條線不能經過其它棋子),而且線的轉折次數不超過兩次,那麼這兩個棋子就可以在棋盤上消去。不好意思,由於我以前沒有玩過連連看,諮詢了同學的意見,連線不能從外面繞過去的,但事實上這是錯的。現在已經釀成大禍,就只能將錯就錯了,連線不能從外圍繞過。
玩家鼠標先後點擊兩塊棋子,試圖將他們消去,然後遊戲的後臺判斷這兩個方格能不能消去。現在你的任務就是寫這個後臺程序。
 

Input
輸入數據有多組。每組數據的第一行有兩個正整數n,m(0<n<=1000,0<m<1000),分別表示棋盤的行數與列數。在接下來的n行中,每行有m個非負整數描述棋盤的方格分佈。0表示這個位置沒有棋子,正整數表示棋子的類型。接下來的一行是一個正整數q(0<q<50),表示下面有q次詢問。在接下來的q行裏,每行有四個正整數x1,y1,x2,y2,表示詢問第x1行y1列的棋子與第x2行y2列的棋子能不能消去。n=0,m=0時,輸入結束。
注意:詢問之間無先後關係,都是針對當前狀態的!
 

Output
每一組輸入數據對應一行輸出。如果能消去則輸出"YES",不能則輸出"NO"。
 

Sample Input
3 4 1 2 3 4 0 0 0 0 4 3 2 1 4 1 1 3 4 1 1 2 4 1 1 3 3 2 1 2 4 3 4 0 1 4 3 0 2 4 1 0 0 0 0 2 1 1 2 4 1 3 2 3 0 0
 

Sample Output
YES NO NO NO NO YES
 

Author
lwg
 

Recommend
We have carefully selected several similar problems for you:  1180 1072 1016 1026 1240 

題解:這題坑點好多,一開始的時候給了10s,說明搜索的時候應該情況很多的,因爲這個並不是找一個最優化的解,而是有轉彎次數的限制,這個體現在dfs裏面就不太好判斷,而且剪枝也是這道題的一個很難的地方。首先第一層剪枝,是在get到查詢之後的,如果兩個地方的數字不一樣,也就是連連看的圖案不一樣,那麼不需要搜索直接輸出NO,相應的情況還有該點的數值爲0的情況,也是不需要搜索。其次是在dfs時的剪枝,當轉彎次數超過兩次時,直接判斷當前方向上是否可達目標點,這個剪枝能把運行時間從8k降低到200ms。由於這次搜索的主要key是方向,那麼相應的修改一下模板,沒有用for循環來模擬方向,而是純粹手打,而且對於每種情況優先考慮和它同方向的搜索,不過這個優化的時間不怎麼明顯,大概只有20ms左右。代碼1是隻做了第一層優化的代碼,直接T,運氣好c++可以過,蛤蛤。

代碼:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
int map[1010][1010];
int dx[] = { 0,0,1,-1 };
int dy[] = { 1,-1,0,0 };
int n, m,ans,x2,y2;

void dfs(int x1, int y1, int dir, int times)
{
    if (x1 == x2 && y1 == y2 && times <= 2)
    {
        ans = 1; 
        return;
    }
    if (times > 2)
        return ;
    map[x1][y1] = -1;
    for (int i = 0; i < 4; i++)
    {
        int curx = x1 + dx[i];
        int cury = y1 + dy[i];
        if (curx > 0 && curx <= n && cury > 0 && cury <= m && map[curx][cury] == 0)
        {
            if (i == dir)
                dfs(curx, cury, dir, times);
            else
                dfs(curx, cury, i, times + 1);
        }
    }
    map[x1][y1] = 0;
    return;
}
int main()
{
    //freopen("input.txt", "r", stdin);
    int q, x1,  y1;
    while (scanf("%d%d", &n, &m), !(m == 0 && n == 0))
    {
        //init();
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                scanf("%d", &map[i+1][j+1]);
            }
        }
        scanf("%d", &q);
        for (int i = 0; i < q; i++)
        {
            scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        
            if (map[x1][y1] == map[x2][y2] && map[x1][y1] !=0)
            {
                map[x2][y2] = 0;
                int temp = map[x1][y1];
                ans = 0;
                dfs(x1, y1,  -1, -1);
                if (ans)
                    printf("YES\n");
                else
                    printf("NO\n");
                
                map[x1][y1] = map[x2][y2] = temp;
            }
            else
                puts("NO");
            
            
        }
    }
    return 0;
}


代碼2:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1005;
int map[maxn][maxn], vis[maxn][maxn];
int n, m, x2, y2;
int ans;
//1,2,3,4stands for up,down,left,right
void dfs(int x, int y, int dir, int turn)
{
	if (ans)
		return;
	if (x <= 0 || x > n || y <= 0 || y > m)  //out of map
		return;
	if (turn >= 3)                           //turn out of limit
		return;
	if (x == x2 && y == y2)                  //get the goal
	{
		ans = 1;
		return;
	}
	if (turn == 2)                           //剪枝,轉彎兩次時,看目的點的座標與現在的朝向是否在一個方向上,不在的話就返回  
	{
		if (!((dir == 1 && y < y2 && x == x2)  || (dir == 2 && y > y2 && x == x2) || (dir == 3 && x > x2 && y == y2) || (dir == 4 && x < x2 && y == y2)))
			return;
	}
	if (map[x][y] != 0)                      //barrier
		return;
	if (vis[x][y])                           //visited
		return;


	vis[x][y] = 1;
	if (dir == 1)
	{
		dfs(x, y + 1, 1, turn);
		dfs(x, y - 1, 2, turn + 1);
		dfs(x - 1, y, 3, turn + 1);
		dfs(x + 1, y, 4, turn + 1);
	}
	else if (dir == 2)
	{
		dfs(x, y - 1, 2, turn);
		dfs(x, y + 1, 1, turn + 1);
		dfs(x - 1, y, 3, turn + 1);
		dfs(x + 1, y, 4, turn + 1);
	}
	else if (dir == 3)
	{
		dfs(x - 1, y, 3, turn);
		dfs(x, y + 1, 1, turn + 1);
		dfs(x, y - 1, 2, turn + 1);
		dfs(x + 1, y, 4, turn + 1);
	}
	else if (dir == 4)
	{
		dfs(x + 1, y, 4, turn);
		dfs(x, y + 1, 1, turn + 1);
		dfs(x, y - 1, 2, turn + 1);
		dfs(x - 1, y, 3, turn + 1);
	}

	vis[x][y] = 0;
	return;
}

int main()
{
	//freopen("input.txt", "r", stdin);
	int q, x1, y1;
	while (scanf("%d%d", &n, &m) != EOF, n || m)
	{

		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= m; j++)
			{
				scanf("%d", &map[i][j]);
			}
		}
		scanf("%d", &q);
		while (q--)
		{
			memset(vis, 0, sizeof(vis));
			scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
			ans = 0;
			if (x1 == x2 && y1 == y2)
				puts("NO");
			else if (map[x1][y1] == map[x2][y2] && map[x1][y1])
			{
				dfs(x1, y1 + 1, 1, 0);
				dfs(x1, y1 - 1, 2, 0);
				dfs(x1 - 1, y1, 3, 0);
				dfs(x1 + 1, y1, 4, 0);
				if (ans)
					puts("YES");
				else
					puts("NO");
			}
			else
				puts("NO");
		}
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章