实验目的
实现题1-4 金币阵列问题
实验原理
使用分治法,根据给定阵列初始状态,目标状态,按游戏规则计算从初始状态到目标状态需要的最少变换次数
实验步骤
①先确定某一种行变换T
②经过T变换之后我们不在进行行反转,而是进行列交换
③经过一定的列变换后观察是否和目标矩阵相同,相同则表明变换有效,得到一个变换步骤
④取步骤中的最小值
算法时间复杂度
使用了三重循环,所以为O(n^3)
实验心得
通过这次实验,我学习了如何利用分治法解决复杂的金币问题
完整代码
金币阵列
#include<cmath>
#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<ctime>
#include <fstream>
#define size 200
using namespace std;
int row; //行数
int column; //列数
int count; //交换次数
int min;
int a[size][size]; //初始矩阵
int b[size][size]; //最终矩阵
int c[size][size]; //临时存放矩阵
int found; //初始到最终是否有交换
void trans_row(int x) // 第x行取反
{
int i;
for (i = 0;i<column; i++)
b[x][i] = b[x][i]^1; // 异或取反
::count++;
}
void trans_column(int x, int y) // 交换x和y列
{
int i;
int temp;
for(i = 0; i < row; i++)
{
temp=b[i][x];
b[i][x]=b[i][y];
b[i][y]=temp;
}
if (x != y)
::count++;
}
bool same_column(int x,int y) //比较x和y列是否相同
{
int i;
for(i = 0; i <row; i++)
if (a[i][x] != b[i][y])
return 0;
return 1;
}
void copy(int a[size][size], int b[size][size]) // 拷贝数组
{
for (int i = 0; i <row; i++)
for (int j = 0; j < column; j++)
a[i][j] = b[i][j];
}
int main()
{
ifstream iFile("input.txt",ios::in);
if(!iFile)
{
cerr<<"open error!"<<endl;
exit(1);
}
int i,j,k,p;
int exchgmin[size];
int num; //输入几组数据
iFile>>num;
for(i=0;i<num;i++)
{
clock_t start,end;
start = clock();
//计时
iFile>>row;
iFile>>column;
for(j=0;j<row;j++)
for(k=0;k<column;k++)
iFile>>a[j][k];
for(j=0;j<row;j++)
for(k=0;k<column;k++)
iFile>>b[j][k];
copy(c,b); //保护原始数组b
::min=row+column+1;
for(j=0;j<column;j++)
{
copy(b,c); //恢复原始数组b
::count=0; //交换次数清零
trans_column(0,j); //把每一列都假设成为第一列的目标状态,穷举这column中情况
for(k=0;k<row;k++)
{ //如果行不同,则将行转换
if(a[k][0]!=b[k][0])
trans_row(k);
}
int lo[200],flag=0,tot=0;
for(k=0;k<column;k++)
{//穷举其他所有列,如果相同则交换,说明目标状态统一,否则找不到与该列相同,说明不可行
found=0;
tot=0;flag=0;
for(p=k;p<column;p++)
{
if(same_column(k,p))
{
found=1;
if(p==k)
{break;}
lo[tot++]=p;
if(same_column(p,k))
{flag=1;trans_column(k,p);break;}
}
}
if(!found)
break;
else if(!flag && tot)
trans_column(k,lo[0]);
}
if(found&&::count<::min) //如果可行,找出最小值
::min=::count;
}
if(::min<(row+column+1)) //如果交换次数比初始值小,将其保存为当前组的最小交换次数,否则不可实现交换
exchgmin[i]=::min;
else exchgmin[i]=-1;
end = clock();
printf("time=%fms",(double)(end-start)/CLK_TCK);
ofstream out;
out.open("output.txt");
out<<exchgmin[i]<<endl;
out.close();
}
return 0;
}
随机数生成
#include <time.h>
#include <stdlib.h>
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
ofstream out("input_100.txt");
out<<1<<'\n';
out<<100<<" "<<100<<'\n';
srand((unsigned)time(NULL));
for(int i=0;i<200;i++)
{
for(int j=0;j<100;j++)
{
out<<rand()%2<<' ';
}
out<<'\n';
}
out.close();
return 0;
}