您的位置:首页 > 大数据 > 人工智能

UVALive 7263 Today Is a Rainy Day(BFS预处理)

2017-12-12 00:15 411 查看


        非常聪明的搜索。

        大致题意:给你很多1~6的数字组合表示的状态,一个起始状态一个终止状态。每一步你可以选择两种操作中的一种,一是选择其中一个位置的数字变成另一个,二是选择一类数字,把所有该数字变成另外一个数字。

        首先,很显然的,最优答案一定是先做第二个操作,然后再做第一个操作,然后操作数肯定小于数字的长度。于是,根据这个,我们便是可以枚举所有的第二个操作的变换。注意到每个数字只会变成其他五个数字,而且不会往回变,所以总的变换个数就是6!个,但是实际为了方便不考虑那么多,认为有6^6种变换。这里的变换可以变相理解为类似polya里面的置换的个数,而且同样也都用广搜取搜索。然后顺势计算出到每个状态的最少步骤数。

        预处理完毕之后,我们枚举每一种变换,然后接下来就是只有第一个操作了。首先,我们对其实状态按照枚举出来的变换进行变换,然后在看变换之后的状态与最终状态不同的个数,这个不同的个数加上变换的步数就是当前变换的步骤数,找到一个最小的即可。具体在实现的时候,由于有强迫症,又把广搜写成了dijkstra+优先队列的形式,其实完全没有必要,快不了多少。然后这个变换的表示方法,这里利用一个6位的六进制数去表示。具体见代码:

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
#define M 46656
#define N 120
using namespace std;

int dp[M],c[6],src
,dst
,n;
typedef pair<int,int> P;
char s
,t
;

int turn_to(int *c)
{
int res=0;
for(int i=0;i<6;i++)
res=res*6+c[i];
return res;
}

void turn_back(int s,int *c)
{
for(int i=5;i>=0;i--)
c[i]=s%6,s/=6;
}

void bfs()
{
priority_queue<P,vector<P>,greater<P> > q;
memset(dp,INF,sizeof(dp)); int tmp[6];
for(int i=0;i<6;i++) c[i]=i;
int s=turn_to(c); dp[s]=0; q.push(P{0,s});
while(!q.empty())
{
int w=q.top().first;
int ns=q.top().second;
q.pop(); if (dp[ns]<w) continue;
turn_back(ns,c);
for(int i=0;i<6;i++) //枚举第二种变换的起止数字
for(int j=0;j<6;j++)
if (i!=j)
{
memcpy(tmp,c,sizeof(c));
for(int k=0;k<6;k++) //改变所有的同类数字
if (tmp[k]==i) tmp[k]=j;
int t=turn_to(tmp);
if (dp[ns]+1<dp[t]) //看状态是否最优,加入队列
{
dp[t]=dp[ns]+1;
q.push(P{dp[t],t});
}
}
}
}

int main()
{
bfs(); //预处理变换及其步骤数
while(~scanf("%s%s",t,s))
{
int len=strlen(s);
for(int i=0;i<len;i++)
{
src[i]=s[i]-'1';
dst[i]=t[i]-'1';
}
int ans=INF;
for(int i=0;i<M;i++) //枚举所有的变换
{
int res=dp[i];
turn_back(i,c);
if (res>=ans) continue;
for(int j=0;j<len;j++)
{
if (c[src[j]]!=dst[j]) res++;
if (res>=ans) break;
}
ans=min(res,ans);
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: