您的位置:首页 > 其它

ZOJ 3755 Mines 回溯+剪枝

2014-07-16 22:02 603 查看
Mines
Time Limit: 2 Seconds      Memory Limit: 65536 KB
As a small-game fan, Flandre loves playing the Mine-sweeping very much. He spends 23 hours playing the lowest level of Mine-sweeping every day. 

One day, when Flandre is playing Mine-sweeping, a strange idea comes to him: 

"Can I just calculate the minimum number of the mine in current state of the game ?" 



To simplify this problem, we suppose the map is a N*(M*2+1) matrix
and there are some mines in the grids of odd columns. You have got all the messages about the even columns which are represented as a N * M number
matrix. 
For example: N = 3, M = 2(# represent the mines, number means how many mines around it) 
# 2 1 2 # 
2 4 # 3 0 
# 3 # 2 0 
the messages about the even columns are: 
2 2 
4 3 
3 2 
Your task is to calculate the minimum number of mines with the messages matrix.

Input

There are multiple test cases. For each test case: 

The first line contains two integers N(1≤ N≤ 10), M(1≤ M≤ 10) 

Then followed by N lines, each line contain M integers represent the messages matrix. 

Process to the end of input.

Output

For each the case, print the minimum number of mines.

Sample Input

3 2
2 2
4 3
3 2

Sample Output

4


解题思路:1.本人小菜,直接建图回溯……

2.大神,状态压缩dp做的……

/********************************
*	作者:Linfly
*	时间:2014-07-16 12:26
********************************/
#include <iostream>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <algorithm>
#include <stack>
#include <cstring>
using namespace std;

#define MAXN 50
int m[MAXN][MAXN];
int N,M;
int result;

int dx[6]={-1, 0, 1,-1,0,1};
int dy[6]={-1,-1,-1, 1,1,1};

int CalMines(int x, int y)
{
int num = 0;
for (int i = 0; i<6; i++)
{
num += m[x + dx[i]][y + dy[i]];
}
return -num;
}
void Search(int currpos, int currmine)
{
if (currmine > result) //当前布雷数超过最大雷数
return ;
if (currpos == (N+1)*(M*2+1)) //完成布雷
{
for (int i = N*(M*2+1)+1; i<(N+1)*(M*2+1); i+=2) //检验最后一行布雷情况
{
int x = i/(M*2+1);
int y = i%(M*2+1);
if (CalMines(x,y) != m[x][y])
return ;
}
if (currmine < result)
result = currmine;
return ;
}

int x = currpos/(M*2+1); //计算当前位置的坐标
int y = currpos%(M*2+1);
if (y&1 == 1) //当前位置为周边雷数字
{

//cout << "(" << x << "," << y <<")" << CalMines(x,y)<< ")" ;
if (CalMines(x,y) > m[x][y]) //当前位置数的周边雷多了
return ;
/*
cout << "+++++++++++++++++++ " << currpos << endl;
for (int i = 0; i<N+2; i++)
{
for (int j = 0; j<=M*2; j++)
{
cout << m[i][j];
}
cout << endl;
}
cout << "++++++++++++++++++++++++++++++" << endl;
*/
Search(currpos+1, currmine); //搜索下一个位置
}
else
{
if (y>0&&x>1 && CalMines(x-1,y-1) == m[x-1][y-1]) //左上角
{
Search(currpos+1, currmine);
}
else if(y>0&&x>1 && CalMines(x-1,y-1) == m[x-1][y-1]-1)
{
m[x][y] = -1;
Search(currpos+1, currmine+1);
m[x][y] = 0;
}
else  if (y>0&&x>1)
{
return ;
}
else
{
m[x][y] = -1;
Search(currpos+1, currmine+1);
m[x][y] = 0;
Search(currpos+1, currmine);
}
}

}

int main()
{
while (cin >> N >> M)
{
result = 0xfffffff;
memset(m, 0, sizeof(m));
for (int i = 1; i<=N; i++)
{
for (int j = 0; j<M; j++)
{
cin >> m[i][j*2+1];
}
}
/*
for (int i = 0; i<N+2; i++)
{
for (int j = 0; j<=M*2; j++)
{
cout << m[i][j];
}
cout << endl;
}*/
Search(M*2+1, 0);
cout << result << endl;
}
return 0;
}


</pre>

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  zoj 搜索