HDOJ 1175 连连看消除-寻路算法


http://acm.hdu.edu.cn/showproblem.php?pid=1175
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

X. DFS
http://blog.csdn.net/iaccepted/article/details/24023215
题意很简单,就是我们平时玩的连连看的游戏规则,刚开始用的广搜,刚开始的剪枝不高效导致爆掉队列,使得内存超限,后来发现,bfs先遍历的点不一定是弯数少的点,这样的话如果不专门来更新的话,就会出现运行结果跟搜索顺序有关,是左上右下还是左下右上等等序列。因为至多两个弯,而数据量是1000*1000的,用dfs搜索的时候,只要找到合法解就行,不需要找弯数最少等最优情况,所以只要找到合法解就进行全局标记,这样其他就不需要搜索了,综合的效率其实非常高,大约在o(kn)级别,而且k不很大,具体也不好推算。后来又加了一个剪枝,即当弯数为二时,若此时点的方向不能直接到达目标点就减去此点,很好理解,因为不满足的话到目标点就必须要拐弯,所以弯数就会超过2,但此剪枝的效率并不高,节省大约20mm。
const int MAX = 1003;
const int dirx[5] = {0,0,1,0,-1};
const int diry[5] = {0,1,0,-1,0};

bool visit[MAX][MAX];
int map[MAX][MAX];
int wan[MAX][MAX];
int n,m,bx,by;
bool mark;

bool yes(int x,int y,int dir){
 int dx = bx - x;
 int dy = by - y;
 if(dx!=0)dx = dx/abs(dx);
 if(dy!=0)dy = dy/abs(dy);
 if(dx==dirx[dir] && dy==diry[dir])return true;
 else return false;
}

void dfs(int x,int y,int cnt,int dir){
 int i,tx,ty;
 if(mark)return;
 if(x<1 || y<1 || x>n || y>m || cnt>2)return;
 //注意下面几个剪枝的顺序,顺序搞错了就会出错,因为最后一个元素非0
 if(x==bx && y==by){
  mark = true;
  return;
 }
 if(cnt==2 && !yes(x,y,dir))return;//这个剪枝不强力,加了此剪枝时间只减少了18ms
 if(map[x][y]!=0)return;
 if(wan[x][y]!=-1 && wan[x][y]<=cnt)return;
 wan[x][y] = cnt;
 for(i=1;i<=4;++i){
  tx = x + dirx[i];
  ty = y + diry[i];
  if(dir!=i){
   dfs(tx,ty,cnt+1,i);
  }else{
   dfs(tx,ty,cnt,i);
  }
 }
}

int main(){
// freopen("in.txt","r",stdin);
 int i,j,t,ax,ay;
 while(scanf("%d %d",&n,&m)!=EOF){
  if(n==0 && m==0)break;
  for(i=1;i<=n;++i){
   for(j=1;j<=m;++j){
    scanf("%d",&map[i][j]);
   }
  }
  scanf("%d",&t);
  while(t--){
   memset(wan,-1,sizeof(wan));
   scanf("%d %d %d %d",&ax,&ay,&bx,&by);
   mark = false;
   if(map[ax][ay]!=map[bx][by] || map[ax][ay]==0){
    printf("NO\n");
    continue;
   }
   wan[ax][ay] = 0;
   for(i=1;i<=4;++i){
    dfs(ax+dirx[i],ay+diry[i],0,i);
   }
   if(mark){
    printf("YES\n");
   }else{
    printf("NO\n");
   }
  }
 }
 
    return 0;
}
http://www.cnblogs.com/Lee-geeker/p/3234419.html
这题在DFS的同时必须考虑剪枝,,给出三个别人的代码,一个耗时7秒多,一个2秒多,最后一个只有46MS,相差甚大,都是剪枝的功劳。

 const int MAX =1002;
 4 bool flag = false;
 5 bool vist[MAX][MAX];
 6 int s,e,map[MAX][MAX];
 7 int dir[5][3]={{1,0},{0,1},{-1,0},{0,-1}};
 8 void DFS(int x,int y,int cnt,int d)
 9 {
10     if(cnt>2||vist[x][y]||flag)return;
11     vist[x][y] = true;
12     for(int i = 0;i < 4;i++)
13     {
14         int a,b,t;
15         a = x + dir[i][0];
16         b = y + dir[i][1];
17         if(d!=i) t = cnt +1;
18         else t = cnt;
19         if(a==s&&b==e&&t<=2)
20         {flag = true;return ;}      //printf("x-%d y-%d a-%d b-%d\n",x,y,a,b);
21         if(!map[a][b]&&!vist[a][b])
22           DFS(a,b,t,i);
23     }
24     vist[x][y] = false;
25 }
26 int main()
27 {
28     //freopen("Input.txt","r",stdin);
29     //freopen("Output.txt","w",stdout);
30     int n,m,u,v,q;
31     while(scanf("%d%d",&n,&m),(n||m))
32     {
33         memset(map,-1,sizeof(map));
34         for(int i = 1;i <= n;i++)
35           for(int j = 1;j <= m;j++)
36             scanf("%d",&map[i][j]);
37         scanf("%d",&q);
38         while(q--)
39         {
40             scanf("%d%d%d%d",&u,&v,&s,&e);
41             flag = false;
42             memset(vist,false,sizeof(vist));
43             if(map[u][v]!=map[s][e]||map[u][v]==0);
44             else
45               DFS(u,v,-1,-1);
46             if(flag)
47               puts("YES");
48             else
49               puts("NO");
50         }
51     }
52     return 0;
53 }
//【解题思路】:dfs+剪枝。其实没什么好说的,有几个要注意的地方,第一个是判重,第二个是记住最多仅能够进行两次转向。切记,在判断到达目标的时候,需要判断其转向次数是否超过两次,表示个人在此处wa了两次。
纯暴力版过了之后。有一个剪枝是:在转向两次之后,因为不可转向,所以接下来必须与之前的方式保持一致,这个优化减少了5s左右的时间,原先是7000ms,现在是2000ms。

1。首先需要判断给定的俩个棋子是否相同
2。如果给定的坐标没有棋子直接输出NO
3。如果给定的坐标是同一个,也直接输出NO。。不知道测试数据里有没有这么恶心的数据,不过小心为上吧。。
3。本题搜索需要一点方向感。盲目搜索必定超时,因为本题可以进行俩次转向。。所以可以分为三种情况。我用turn来标记转向的次数
turn=0 则直接进行下一步搜索。
turn=1 则需要判断 状态的方向 dir 是否与 需要寻找的棋子位置反向了。。如果反向则放弃搜索、、
turn=2 则判断是否和目标棋子在一条直线上,而且需要判断方向是否一致。。否则放弃搜索。。
int n,m;
int move[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
bool used[1005][1005];
int flag;
struct State
{
    int x;
    int y;
    int dir;
    int turn;
    int step;
};
State start;
State end;
int map[1005][1005];
bool Judge(State t)
{
    if(t.x==end.x&&t.y==end.y)
        return 1;
    if(t.turn==0)
        return 1;
    if(t.turn==1)
    {
        if(t.x>end.x&&t.dir==1)
            return 0;
        if(t.y>end.y&&t.dir==3)
            return 0;
        if(t.x<end.x&&t.dir==0)
            return 0;
        if(t.y<end.y&&t.dir==2)
            return 0;
        return 1;
    }
    if(t.turn==2)
    {
        if(t.x==end.x)
        {
            if(t.y>end.y&&t.dir==2)
                return 1;
            if(t.y<end.y&&t.dir==3)
                return 1;
        }
        if(t.y==end.y)
        {
            if(t.x>end.x&&t.dir==0)
                return 1;
            if(t.x<end.x&&t.dir==1)
                return 1;
        }
        return 0;
    }
    return 1;
}
void DFS(State t)
{
    if(flag)
        return;
    if(t.turn>2)
        return;
    if(t.x==end.x&&t.y==end.y)
    {
        flag=1;
        return;
    }
    int x,y;
    State temp;
    if(t.step==0)
    {
        for(int i=0;i<4;i++)
        {
            temp.x=t.x+move[i][0];
            temp.y=t.y+move[i][1];
            if(temp.x<=0||temp.y<=0||temp.x>n||temp.y>m||used[temp.x][temp.y]==1)
                continue;
            
            temp.dir=i;
            temp.turn=0;
            temp.step=t.step+1;
            
            if(Judge(temp)==0)
                continue;
            
            used[temp.x][temp.y]=1;
            DFS(temp);
            used[temp.x][temp.y]=0;
        }
        return;
    }
    if(map[t.x][t.y]!=0)
        return;
    for(int i=0;i<4;i++)
    {
        temp.x=t.x+move[i][0];
        temp.y=t.y+move[i][1];
        if(temp.x<=0||temp.y<=0||temp.x>n||temp.y>m||used[temp.x][temp.y]==1)
            continue;
        if(t.dir!=i)
        {
            temp.dir=i;
            temp.turn=t.turn+1;
        }else
        {
            temp.dir=t.dir;
            temp.turn=t.turn;
        }
        temp.step=1;
        if(Judge(temp)==0)
            continue;
        
        used[temp.x][temp.y]=1;
        DFS(temp);
        used[temp.x][temp.y]=0;
    }
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    int t;
    while(scanf("%d %d",&n,&m))
    {
        if(n==0&&m==0)
            return 0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&map[i][j]);
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d %d %d %d",&start.x,&start.y,&end.x,&end.y);
            if(start.x==end.x&&start.y==end.y)
            {
                printf("NO\n");
                continue;
            }
            if(map[start.x][start.y]!=map[end.x][end.y]||map[start.x][start.y]==0||map[end.x][end.y]==0)
            {
                printf("NO\n");
                continue;
            }
            memset(used,0,sizeof(used));
            used[start.x][start.y]=1;
            start.turn=0;
            start.step=0;
            flag=0;
            DFS(start);
            if(flag)
                printf("YES\n");
            else
                printf("NO\n");
        }
    }
    return 0;
}

X. BFS
http://www.cppblog.com/mythit/archive/2009/04/29/81497.html?opt=admin
一看题目就知道是用bfs,但是要注意几个问题:bfs是按层次进行搜索,得到的从起点到终点的路径(如果存在的话)是最短的。题目中说这条路径最多只能转向2次,有一些情况可能得到了从起点到终点的路径,但是它的转向次数已经超过的2次,这样这条路径就不符合要求,得重新找一条。一个一般的结论:如果某一点记录的转向次数大于当前路径在该点的转向次数,那么还能从该点再发出一条路径来查找。可以用一个二维数组hash[n][n]来状态判重,这个数组里存的数值就是某条路径在该点的转向次数,if(hash[x][y]>=now.turn) q.push(now);还有个需要注意的就是能连上的点并没有从图中消失,所以每条查询语句都是独立的。(我把它当成真正的连连看来做,结果WA了10次)
5 const int N = 1001;
 6 bool flag;
 7 int n,m,sx,sy,ex,ey;
 8 int hash[N][N],map[N][N];
 9 int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
10 struct node{
11     int x,y,turn,d;
12 }start;
13 queue<node> q;
14
15 inline bool in(const node &p){
16     if(p.x<0 || p.y<0 || p.x>=n || p.y>=m)
17         return false;
18     return true;
19 }
20 void bfs(){
21     node now,t;
22     while(!q.empty()){
23         now=q.front(),q.pop();
24         if(now.x==ex && now.y==ey && now.turn<=2){
25             flag=true;
26             return;
27         }
28         for(int i=0;i<4;i++){
29             t.x=now.x+dir[i][0],t.y=now.y+dir[i][1];
30             if(now.d==i)
31                 t.turn=now.turn,t.d=now.d;
32             else
33                 t.turn=now.turn+1,t.d=i;
34             if(in(t) && (map[t.x][t.y]==0||t.x==ex&&t.y==ey) && hash[t.x][t.y]>=t.turn)
35                 hash[t.x][t.y]=t.turn,q.push(t);
36         }
37     }
38 }
39 int main(){
40     int i,j,t;
41     while(scanf("%d %d",&n,&m),n||m){
42         for(i=0;i<n;i++)
43             for(j=0;j<m;j++) scanf("%d",&map[i][j]);
44         scanf("%d",&t);
45         while(t--){
46             scanf("%d %d %d %d",&sx,&sy,&ex,&ey);
47             sx--,sy--,ex--,ey--;
48             if((map[sx][sy]!=map[ex][ey]) || map[sx][sy]==0 || map[ex][ey]==0 || (sx==ex&&sy==ey)){
49                 puts("NO");
50                 continue;
51             }
52             for(i=0;i<n;i++)
53                 for(j=0;j<m;j++) hash[i][j]=11;
54             while(!q.empty()) q.pop();
55             for(i=0;i<4;i++){
56                 start.x=sx,start.y=sy,start.turn=0,start.d=i;
57                 q.push(start);
58             }
59             flag=false,hash[sx][sy]=0;
60             bfs();
61             puts(flag ? "YES":"NO");
62         }
63     }
64     return 0;
65 }
http://www.wutianqi.com/?p=2640
http://www.cocos.com/doc/tutorial/show?id=1828

http://rayleung.iteye.com/blog/480020

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts