欢迎大家访问我的老师的OJ———caioj.cn
题面描述
思路
首先给出如何读入数据
while(scanf("%d",&a[1][3])&&a[1][3])solve();
scanf("%d%d%d",&a[1][5],&a[2][3],&a[2][5]);
for(int i=1;i<=7;i++)scanf("%d",&a[3][i]);
scanf("%d%d",&a[4][3],&a[4][5]);
for(int i=1;i<=7;i++)scanf("%d",&a[5][i]);
scanf("%d%d%d%d",&a[6][3],&a[6][5],&a[7][3],&a[7][5]);
如何改变状态
void work(int k)
{
if(k==1)
{
for(int i=1;i<8;i++)a[i-1][3]=a[i][3];
a[7][3]=a[0][3];
}
else if(k==2)
{
for(int i=1;i<8;i++)a[i-1][5]=a[i][5];
a[7][5]=a[0][5];
}
else if(k==3)
{
for(int i=7;i;i--)a[3][i+1]=a[3][i];
a[3][1]=a[3][8];
}
else if(k==4)
{
for(int i=7;i;i--)a[5][i+1]=a[5][i];
a[5][1]=a[5][8];
}
else if(k==5)
{
for(int i=7;i;i--)a[i+1][5]=a[i][5];
a[1][5]=a[8][5];
}
else if(k==6)
{
for(int i=7;i;i--)a[i+1][3]=a[i][3];
a[1][3]=a[8][3];
}
else if(k==7)
{
for(int i=1;i<8;i++)a[5][i-1]=a[5][i];
a[5][7]=a[5][0];
}
else
{
for(int i=1;i<8;i++)a[3][i-1]=a[3][i];
a[3][7]=a[3][0];
}
}
这道题的输入是真的鬼畜啊。
直接爆搜肯定不行。
所以我们用
IDA*
\operatorname{IDA*}
IDA*来爆搜。
首先限制深度,
设8个数中最多出现次数的数字为
k
k
k,设与
k
k
k不同的个数为
m
m
m个
通过观察可以发现,我们取m为估价函数。因为我们至少要使这
m
m
m个数变为
k
k
k才能满足条件.
总而言之,当"当前操作次数+估价>
dep
\large\operatorname{dep}
dep"时,就回溯。
另外,有一个重要剪枝,不要执行上一次执行的操作的逆操作,因为这样等价于无效。
int c=ans[len]-'A'+1;
if(c==1&&i==6)continue;
else if(c==2&&i==5)continue;
else if(c==3&&i==8)continue;
else if(c==4&&i==7)continue;
else if(c==5&&i==2)continue;
else if(c==6&&i==1)continue;
else if(c==7&&i==4)continue;
else if(c==8&&i==3)continue;
完整代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
using namespace std;
const char A[9]={'0','A','B','C','D','E','F','G','H'};
int a[11][11],dep;
char ans[121];
void work(int k)
{
if(k==1)
{
for(int i=1;i<8;i++)a[i-1][3]=a[i][3];
a[7][3]=a[0][3];
}
else if(k==2)
{
for(int i=1;i<8;i++)a[i-1][5]=a[i][5];
a[7][5]=a[0][5];
}
else if(k==3)
{
for(int i=7;i;i--)a[3][i+1]=a[3][i];
a[3][1]=a[3][8];
}
else if(k==4)
{
for(int i=7;i;i--)a[5][i+1]=a[5][i];
a[5][1]=a[5][8];
}
else if(k==5)
{
for(int i=7;i;i--)a[i+1][5]=a[i][5];
a[1][5]=a[8][5];
}
else if(k==6)
{
for(int i=7;i;i--)a[i+1][3]=a[i][3];
a[1][3]=a[8][3];
}
else if(k==7)
{
for(int i=1;i<8;i++)a[5][i-1]=a[5][i];
a[5][7]=a[5][0];
}
else
{
for(int i=1;i<8;i++)a[3][i-1]=a[3][i];
a[3][7]=a[3][0];
}
}
int gj()
{
int num[4];num[1]=num[2]=num[3]=0;
for(int i=3;i<=5;i++)
for(int j=3;j<=5;j++)
if(!(i==4&&j==4))
{
++num[a[i][j]];
}
return 8-max(num[1],max(num[2],num[3]));
}
int len;
bool dfs(int now)
{
int cnt=gj();
if(!cnt)return 1;
if(now+cnt>dep)return 0;
int b[11][11];
memcpy(b,a,sizeof(a));
for(int i=1;i<9;i++)
{
if(len!=0)
{
int c=ans[len]-'A'+1;
if(c==1&&i==6)continue;
else if(c==2&&i==5)continue;
else if(c==3&&i==8)continue;
else if(c==4&&i==7)continue;
else if(c==5&&i==2)continue;
else if(c==6&&i==1)continue;
else if(c==7&&i==4)continue;
else if(c==8&&i==3)continue;
}
ans[++len]=A[i];work(i);
if(dfs(now+1))return 1;
--len;
memcpy(a,b,sizeof(b));
}
return 0;
}
void solve()
{
scanf("%d%d%d",&a[1][5],&a[2][3],&a[2][5]);
for(int i=1;i<=7;i++)scanf("%d",&a[3][i]);
scanf("%d%d",&a[4][3],&a[4][5]);
for(int i=1;i<=7;i++)scanf("%d",&a[5][i]);
scanf("%d%d%d%d",&a[6][3],&a[6][5],&a[7][3],&a[7][5]);
dep=0;len=0;
while(!dfs(0))++dep;
if(!dep)puts("No moves needed");
else
{
for(int i=1;i<=len;i++)putchar(ans[i]);
puts("");
}
printf("%d\n",a[3][3]);
}
int main()
{
while(scanf("%d",&a[1][3])&&a[1][3])solve();
return 0;
}