金币阵列问题

问题描述:
有mxn(m <= 100,n <= 100)个金币在桌面上排成一个m行n 列的金币阵列。每一枚金
币或正面朝上或背面朝上。用数字表示金币状态,0表示金币正面朝上,1 表示背面朝上。
金币阵列游戏的规则是:
(1)每次可将任一行金币翻过来放在原来的位置上;
(2)每次可任选2 列,交换这2 列金币的位置。
算法设计:
给定金币阵列的初始状态和目标状态,计算按金币游戏规则,将金币阵列从初始状态变
换到目标状态所需的最少变换次数。


数据输入:
文件中有多组数据。文件的第1行有1 个正整数k,表示有k 组数据。每组数据的第1 行有2 个正整数m 和n。

以下的m行是金币阵列的初始状态,每行有n 个数字表示该行金币的状态,0 表示金币正面朝上,1 表示背面朝上。

接着的m行是金币阵列的目标状态。


«结果输出:
相应数据无解时输出-1。

输入文件示例
2
4 3
1 0 1
0 0 0
1 1 0
1 0 1
1 0 1
1 1 1
0 1 1
1 0 1
4 3
1 0 1
0 0 0
1 0 0
1 1 1
1 1 0
1 1 1
0 1 1
1 0 1

输入文件示例
2
-1

 

1.思路是从1-n,逐列枚举其为第1列。然后再对不满足的行进行变化
最后的差别会只在列上面。
代码采用了hash,所以复杂度位O(mn^2),复杂到没有明显的bug ^_^
下面这个链接:最直接的写法,简单到明显没有bug

http://blog.csdn.net/sftxlin/article/details/7282645

 

“There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. And the other way is to make it so complicated that there are no obvious deficiencies.”- C.A.R. Hoare

  设计软件有两种方法:一种是简单到明显没有缺陷,另一种复杂到缺陷不那么明显。—— 托尼·霍尔

 

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <ctime>
#include <cctype>
#include <climits>
#include <map>
using namespace std;
const int maxn=108;
char a[maxn][maxn],b[maxn][maxn],temp[maxn][maxn];
int s1[maxn],s2[maxn];

const int N=136;
const int mod = 131;
unsigned int ELFhash(char* url)
{
	unsigned int h = 0, g;
	while (*url) {
		h = (h << 4) + *url++;
		g = h & 0xF0000000;
		if (g)
			h ^= g >> 24;
		h &= ~g;
	}
	return h % mod;
}
char mp[N][maxn];
int head[N], nxt[N], e = 1;//e=0;
int msn[N];
inline int Find_hash(int u,char* x)
{
	for (int i = head[u]; i ; i = nxt[i])
		if (!strcmp(mp[i], x))
			return i;
	return 0;
}
inline int Insert_hash(int u,char* x)
{
	strcpy(mp[e], x);
	nxt[e] = head[u];
	head[u] = e++;
	return head[u];
}
//hash 仅调用一次,可不初始化
void init_hash()
{
	//i!=-1
	e = 1;//e=0;
	memset(head, 0, sizeof(head[0])*mod);
	//mem(,-1,)
}

int m,n,nCount;
int Rchar()
{
	int c;
	while (!isdigit(c = getchar()));
	return c;
}

int init();
void solve();
int main()
{
	int t;scanf("%d",&t);
	while(t--)
	{
		if(init() != -1) solve();
		else puts("-1");
	}
	return 0;
}
void input(char a[maxn][maxn],int s1[])
{
	memset(s1,0,sizeof(s1[0])*m);
	for(int i=0;i<m;i++)
	{
		for(int j=0;j<n;j++)
		{
			char c=Rchar();
			a[j][i]=c;
			if(c == '1') s1[i]++;
		}
	}
	for(int i=0;i<n;i++) a[i][m]='\0';
}
void ChangeRow(int c)
{
	for(int i=0;i<n;i++)
	{
		temp[i][c]='1'-temp[i][c]+'0';
	}
}
inline void SwapCol(char s1[],char s2[])
{
	for(int i=0;i<m;i++)
	{
		char t=s1[i];
		s1[i]=s2[i];
		s2[i]=t;
	}
}
int init()
{
	scanf("%d%d",&m,&n);
	input(a,s1);
	input(b,s2);
	nCount=0;
	//变换成个数相同的0,1
	for(int i=0;i<m;i++)
	{
		if(s1[i]==s2[i]) continue;
		if(n-s1[i] == s2[i])
		{
			nCount++;
			for(int j=0;j<n;j++)
			{
				a[j][i]='1'-a[j][i]+'0';
			}
		}
		else return -1;
	}
	return 1;
}
//判断是否可行,并求最小值O(n^2)
int JudgeAndCount()
{
	//求出每列对应的映射值
	static int ms[N];
	memcpy(ms,msn,sizeof(ms));
	for(int i=0;i<n;i++)
	{
		int u=ELFhash(temp[i]);
		int id,t=Find_hash(u,temp[i]);
//检测结果数组有的列,变换后的数组是否都有

		if(t == 0) return -1; 
		else id=t;
		ms[id]--;

		if(ms[id] < 0) return -1;
		s1[i]=id;
	}
//贪心交换,结果是最优的
	int cnt=0;
	for(int i=0;i<n;i++)
	{
		if(s1[i] != s2[i]) 
		for(int j=i+1;j<n;j++)
		{
			if(s1[j] == s2[i] &&  s1[j] != s2[j]) 
			{
				cnt++;
				swap(s1[i],s1[j]);
				break;
			}
		}
	}
	return cnt;
}
//保证第一列完全一样,对行做变化
int KeepFirstCol()
{
	int cnt=0;
	for(int i=0;i<m;i++)
	{
		if(temp[0][i] != b[0][i]) 
		{
			cnt++;
			ChangeRow(i);
		}
	}
	return cnt;
}

//O(n^3)
void solve()
{
	//对结果数组进行变化,保留映射值
	init_hash();
	memset(msn,0,sizeof(msn));
	for(int i=0;i<n;i++) 
	{
		int u=ELFhash(b[i]);
		int id,t=Find_hash(u,b[i]);
		if(t == 0) id=Insert_hash(u,b[i]);
		else id=t;
		msn[id]++;
		s2[i]=id;
	}

	int minv=INT_MAX;
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++) strcpy(temp[j],a[j]);
		int t,ans=nCount;
		//依次以作为第一列
		if(i!=0) 
		{
			SwapCol(temp[0],temp[i]);
			ans++;
		}
		ans+=KeepFirstCol();
		if((t=JudgeAndCount()) == -1) continue;
		ans+=t;
		if(ans < minv) minv=ans;
	}
	printf("%d\n",minv == INT_MAX? -1: minv);
}

 

posted on 2012-04-28 10:43  Blazebird  阅读(921)  评论(0编辑  收藏  举报

导航