ZOJ 3781 Paint the Grid Reloaded 题解 (dfs缩点+BFS)

21 篇文章 1 订阅

Paint the Grid Reloaded

Time Limit: 2 Seconds       Memory Limit: 65536 KB

Leo has a grid with N rows and M columns. All cells are painted with either black or white initially.

Two cells A and B are called connected if they share an edge and they are in the same color, or there exists a cell C connected to both A and B.

Leo wants to paint the grid with the same color. He can make it done in multiple steps. At each step Leo can choose a cell and flip the color (from black to white or from white to black) of all cells connected to it. Leo wants to know the minimum number of steps he needs to make all cells in the same color.

Input

There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:

The first line contains two integers N and M (1 <= NM <= 40). Then N lines follow. Each line contains a string with N characters. Each character is either 'X' (black) or 'O' (white) indicates the initial color of the cells.

Output

For each test case, output the minimum steps needed to make all cells in the same color.

Sample Input
2
2 2
OX
OX
3 3
XOX
OXO
XOX
Sample Output
1
2
Hint

For the second sample, one optimal solution is:

Step 1. flip (2, 2)

XOX
OOO
XOX

Step 2. flip (1, 2)

XXX
XXX
XXX

题意:这题就两种颜色,颜色相同且有公共边的(或者通过另一个相同的颜色连接)为一个连通块,如果翻转其中一个,与它在同一个连通块里的都要改变颜色,求达到相同颜色的最小步数。

思路转自:http://blog.csdn.net/nyist_zxp/article/details/24253379

解题思路:dfs ( 建图) + bfs ( 寻找最优解 ) .

1)  dfs( 建图 ) ,因为翻转的时候每翻转连通块中一个整个连通块都翻转,这样你可以将其看成一个有边相连的无向图,每个边的两个顶点颜色都不一样。

              转化=======〉                 

 

 

2)  bfs( 寻找最优解 ) , 建完图后就需要翻转计算最优解,可以枚举从每一点开始翻转所得到的最小步数,那怎样寻找最小步数 ? 假如从 v 这个顶点出发,那么与 v 相邻的顶点颜色必定都与 v 相反,so~> 你只需要把 v的颜色翻转,v与它相邻的所有顶点都是同一个颜色,这时可以把这些顶点看成一个连通块(顶点),再向四周扩展,再次扩展时,周围的颜色必定与此连通块颜色相反,再将它变成与周围顶点相同的颜色,这样又合并成为一个连通块……这样一直进行下去取最大步数。最后从最大步数中取出最小的步数即为最优解。其实就是求每个点的最大深度。。。


这题dfs缩点,bfs找答案还是很好的。。


#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 45;
const int INF = 1e9;
int book[maxn][maxn], cnt, bookv[maxn*maxn], n, m;
vector<int> v[maxn*maxn];
char str[maxn][maxn];
int dir[4][2] = {0,1,0,-1,1,0,-1,0};
struct node
{
    int d, id;
    node() {}
    node(int ii, int dd) : id(ii), d(dd) {}
};
void dfs(int x, int y, int id, char ch)  //id,跟ch在dfs一直是不变的。。。代表当前点的序号,跟颜色
{
    for(int i = 0; i < 4; i++)
    {
        int tx = x + dir[i][0];
        int ty = y + dir[i][1];
        if(tx < 0 || ty < 0 || tx >= n || ty >= m) continue;
        if(str[tx][ty] == ch)
        {
            if(book[tx][ty] == -1)  // 如果颜色相同并且没被缩点,就把他归为id点。。
            {
                book[tx][ty] = id;
                dfs(tx, ty, id, ch);
            }
        }
        else if(book[tx][ty] != -1)  //如果颜色不同, 直接建图。。记得是双向图
        {
            int temp = book[tx][ty];
            v[id].push_back(temp);
            v[temp].push_back(id);
        }
    }
}
int bfs(int id)
{
    queue<node> q;
    q.push(node(id, 0));
    int ans = -1;
    memset(bookv, 0, sizeof(bookv));
    bookv[id] = 1;
    while(!q.empty())
    {
        node p = q.front();
        q.pop();
        ans = max(p.d, ans);
//        cout << ans << endl;
        int u = p.id;
        for(int i = 0; i < v[u].size(); i++)
        {
            if(bookv[v[u][i]]) continue;
            bookv[v[u][i]] = 1;
            q.push(node(v[u][i], p.d+1));
        }
    }
    return ans;
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d", &n, &m);
        for(int i = 0; i < n; i++)
            scanf("%s", str[i]);
        for(int i = 0; i <= n*m; i++)
            v[i].clear();
        memset(book, -1, sizeof(book));
        cnt = 0; //缩点标号
        for(int i = 0; i < n; i++)
            for(int j = 0; j < m; j++)
            {
                if(book[i][j] == -1)  //如果这个点没有被染色,就dfs去缩点。。
                {
                    book[i][j] = cnt;
                    dfs(i, j, cnt, str[i][j]);
                    cnt++;
                }
            }
            int ans = INF;
//            cout << cnt << endl;
//            bfs(5);
            for(int i = 0; i < cnt; i++)  //遍历每个点。。。
            {
                ans = min(ans, bfs(i));
//                cout << bfs(i) << endl;
            }
            printf("%d\n", ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值