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

来源:互联网 发布:网络嗅探器5.5.0 编辑:程序博客网 时间:2024/06/05 12:02

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

22 2OXOX3 3XOXOXOXOX

Sample Output

12

Hint

For the second sample, one optimal solution is:

Step 1. flip (2, 2)

XOXOOOXOX

Step 2. flip (1, 2)

XXXXXXXXX

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

思路转自: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
原创粉丝点击