POJ3279【枚举】

#include<stdio.h>
#include<string.h>
int map[16][16], dp[16][16], an[16][16];
int n, m, dx[4] = {0, 0, 1, -1}, dy[4] = {1, -1, 0, 0};
bool isflip(int x, int y)
{
	int i, cnt = dp[x][y];//本来翻转的次数 
	for(i = 0; i < 4; ++i)
	{
		int nx = x+dx[i];
		int ny = y+dy[i];
		if(nx < 0 || nx >= n || ny < 0 || ny >= m)
		continue;
		cnt += dp[nx][ny];//加上四周的点翻转的次数 
	}
	cnt += map[x][y];// 加上该点原来的状态 
	return cnt&1;//如果是奇数  则需要翻转 
}
int check()
{
	int i, j;
	for(i = 1; i < n; ++i)
	for(j = 0; j < m; ++j)
	if(isflip(i-1, j))//是否需要翻转 
	dp[i][j] = 1;
	for(i = 0; i < m; ++i)
	if(isflip(n-1,i))//如果最后一行有1则失败 
	return -1;
	int ans = 0;
	for(i = 0; i < n; ++i)
	for(j = 0; j < m; ++j)
		ans += dp[i][j];
	return ans;
}
int main()
{
	int i, j, k;
	while(scanf("%d%d", &n, &m) != EOF)
	{
		for(i = 0; i < n; ++i)
		for(j = 0; j < m; ++j)
		scanf("%d", &map[i][j]);
		//枚举第一行的情况
		int cas = 1 << m;
		int ans = 100000000; 
		for(i = 0; i < cas; ++i)//每一个i代表第一行的一种翻转情况 
		{
			//对于每一个i进行暴力翻转
			//如果最后一行全部翻转成功记录翻转的最小次数
			//同时记录翻转后的状态 
			memset(dp, 0, sizeof(dp));
			for(j = 0; j < m; ++j)
			if(i & (1<<j))
			dp[0][j] = 1;
			int temp = check();
			if(temp == -1)
			continue;
			else
			{
				if(temp < ans)
				{
					ans = temp;
					memcpy(an, dp, sizeof(dp));
				}
			}
		} 
		if(ans == 100000000)
		printf("IMPOSSIBLE\n");
		else
		{
			for(i = 0; i < n; ++i)
			for(j = 0; j < m; ++j)
			{
				if(j != m-1)
				printf("%d ", an[i][j]);
				else
				printf("%d\n", an[i][j]);
			}
		}
	}
	return 0;
}

题意:给出一个二维矩阵,每个点要么是0要么是1,现在对其中一个点进行翻转,那么这个点四周的点也会随之翻转,现在问最少翻转多少次能将该矩阵翻转为全0 的状态,如果不行则输出IMPOSSIBLE,若可以则输出每个点翻转的次数。

思路:对于二维的矩阵,我们列举第一行的所有情况,因为要求所有状态都为0, 所以当第一行状态确定时,第二行也就随之确定了,以此类推到最后一行,若最后一行状态全为0,则可以保存翻转的次数,若是比先前的小,则要保存当前每个点翻转的次数。最后输出结果。

你可能感兴趣的:(POJ3279【枚举】)