洛谷 P3956 棋盘(BFS)

传送门:Problem P3956

https://www.cnblogs.com/violet-acmer/p/9827010.html

 

题解:

  BFS

  相关变量解释:

    color[maxn][maxn];...................................color[ i ][ j ] : ( i , j )点的颜色,-1代表无色
    dp[maxn][maxn];.......................................dp[ i ][ j ] : 从( 1 , 1 )点到( i , j )点需要花费的最少金币
    magic[maxn][maxn];..................................magic[ i ][ j ] : 判断 ( i , j )点是否使用魔法
    in[maxn][maxn];.........................................in[ i ][ j ] : 判断( i , j )点是否在队列中

  具体步骤:

    初始,将(1,1)点加入队列中;

    (1):保存队头元素并弹出

    (2):每次,判断当前点的上下左右点是否可以通过当前点使dp[ ][ ]变小,如果可以,更新dp[ ][ ],如果被更新的点不在队列中,加入队列

    (3):重复(2)过程,直到队列为空

AC代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<queue>
  4 #include<cstring>
  5 using namespace std;
  6 #define INF 0x3f3f3f3f
  7 #define P pair<int ,int >
  8 #define mem(a,b) memset(a,b,sizeof a)
  9 const int maxn=100+50;
 10 
 11 int m,n;
 12 int color[maxn][maxn];
 13 int dp[maxn][maxn];
 14 bool marge[maxn][maxn];
 15 bool in[maxn][maxn];
 16 queue<P >myqueue;
 17 int dx[4]={-1,1,0,0};
 18 int dy[4]={0,0,-1,1};
 19 bool isSat(int val)
 20 {
 21     return val >= 1 &&val <= m;
 22 }
 23 void Solve()
 24 {
 25     dp[1][1]=0;//初始化dp[1][1],并将其加入到队列中
 26     myqueue.push(P(1,1));
 27     while(!myqueue.empty())//步骤(3)
 28     {
 29         P p=myqueue.front();//步骤(1)
 30         myqueue.pop();
 31         in[p.first][p.second]=false;
 32         for(int i=0;i < 4;++i)//步骤(2)
 33         {
 34             int x=p.first+dx[i];
 35             int y=p.second+dy[i];
 36             if(isSat(x) && isSat(y))
 37             {
 38                 if(!marge[p.first][p.second])//如果当前点的未使用过魔法的,也就意味这当前点的颜色是本身就有的
 39                 {
 40                     if(!marge[x][y])//如果与当前点相邻的点(x,y)也为曾使用过魔法
 41                     {
 42                         if(color[x][y] != -1)//如果点(x,y)有色,但并不是因为魔法而产生的
 43                         {
 44                             //如果当前点可以放缩dp[x][y]
 45                             if(dp[x][y] > dp[p.first][p.second]+(color[x][y] != color[p.first][p.second]))
 46                             {
 47                                 dp[x][y]=dp[p.first][p.second]+(color[x][y] != color[p.first][p.second]);
 48                                 if(!in[x][y])//被放缩的点(x,y)如果不在队列中,加入队列
 49                                     in[x][y]=true,myqueue.push(P(x,y));
 50                             }
 51                         }
 52                         else//如果无色,通过使用魔法将其变为与当前点颜色相同的点,并被放缩了dp[][]
 53                         {
 54                             marge[x][y]=true;
 55                             color[x][y]=color[p.first][p.second];
 56                             dp[x][y]=dp[p.first][p.second]+2;
 57                             if(!in[x][y])
 58                                 in[x][y]=true,myqueue.push(P(x,y));
 59                         }
 60                     }
 61                     else if(dp[x][y] > dp[p.first][p.second]+2)//如果点(x,y)在之前使用过魔法,就需要判断,当前为使用过魔法的点是否可以放缩dp[x][y]
 62                     {
 63                         dp[x][y]=dp[p.first][p.second]+2;
 64                         color[x][y]=color[p.first][p.second];
 65                         if(!in[x][y])
 66                             in[x][y]=true,myqueue.push(P(x,y));
 67                     }
 68                 }
 69                 else if(!marge[x][y] && color[x][y] != -1)//如果当前点的使用过魔法的,也就意味这当前点的颜色是通过魔法变来的,那么,只有当其临近点(x,y)含有的颜色是其本身就有的才有资格判断是否可以被放缩
 70                 {
 71                     if(dp[x][y] > dp[p.first][p.second]+(color[x][y] != color[p.first][p.second]))
 72                     {
 73                         dp[x][y]=dp[p.first][p.second]+(color[x][y] != color[p.first][p.second]);
 74                         if(!in[x][y])
 75                             myqueue.push(P(x,y)),in[x][y]=true;
 76                     }
 77                 }
 78             }
 79         }
 80     }
 81     printf("%d\n",dp[m][m] == INF ? -1:dp[m][m]);
 82 }
 83 void Init()
 84 {
 85     mem(dp,INF);
 86     mem(in,false);
 87     mem(marge,false);
 88     mem(color,-1);
 89 }
 90 int main()
 91 {
 92     scanf("%d%d",&m,&n);
 93     Init();
 94     for(int i=1;i <= n;++i)
 95     {
 96         int x,y;
 97         scanf("%d%d",&x,&y);
 98         scanf("%d",&color[x][y]);
 99     }
100     Solve();
101 }
View Code

 

  

posted @ 2018-10-21 22:01  HHHyacinth  阅读(507)  评论(0编辑  收藏  举报