题意
给出奇数个数,每次把它中间的数取出来放到最左边或最右边,求出最少取多少次可以让这些数是从小到大的。
思路
bfs+hash判重。每次左边右边操作一次,判断之前有没有出现过了,没有就入队。
95分代码(这里hash好像打的不是很好)
#include<cstdio>
#define MAXN 300017
using namespace std;
int n,state[1000001][11],head,tail,hs[MAXN],father[1000001],ans;
int locate(int x)
{
int b=0;
for (int i=1;i<=n;i++)
b=b+state[x][i]*state[x][i-1]*i;
return b%MAXN;
}
bool hash(int x)
{
int f=locate(x),i=0;
while (i<MAXN&&hs[(i+f)%MAXN]>0&&hs[(i+f)%MAXN]!=f) i++;
if (hs[(i+f)%MAXN]==0) {hs[(i+f)%MAXN]=f;return 1;}
else return 0;
}
void left()//左边
{
for (int i=n/2+1;i>=2;i--)
state[tail][i]=state[head][i-1];
state[tail][1]=state[head][n/2+1];
for (int i=n/2+2;i<=n;i++)
state[tail][i]=state[head][i];
}
void right()//右边
{
for (int i=n/2+1;i<n;i++)
state[tail][i]=state[head][i+1];
state[tail][n]=state[head][n/2+1];
for (int i=1;i<n/2+1;i++)
state[tail][i]=state[head][i];
}
int check(int x)
{
for (int i=2;i<=n;i++)
if (state[x][i]<state[x][i-1]) return 0;//判断从小到大
return 1;
}
void Ans(int x)//回溯求答案
{
while (father[x]!=0)
{
ans++;
x=father[x];
}
}
void bfs()
{
if (hash(1)) n=n;//先把初始状态扔进hash表里
head=0;tail=1;
do
{
head++;
tail++;
left();
if (!hash(tail)) tail--;//如果不可以左边我们就不入队
else father[tail]=head;//记录father求答案
if (check(tail)) {Ans(tail);return;}//如果已经从小到大了就退出
tail++;
right();
if (!hash(tail)) tail--;
else father[tail]=head;
if (check(tail)) {Ans(tail);return;}
}
while (head<tail);
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&state[1][i]);
bfs();
ans!=0?printf("%d",ans):printf("No Answer");
}
AC了!
#include<cstdio>
#define MAXN 1000003
using namespace std;
int n,state[1000001][11],head,tail,bs[1000001],mid,a[1000001];
long long hs[MAXN];
bool ok;
long long locate(int a[])
{
long long b=0;
for (int i=1;i<=n;i++) b=(b<<3)+(b<<1)+a[i];
return b;
}
bool hash(int a[])
{
long long f=locate(a);int y=f%MAXN;
while(hs[y]&&hs[y]!=f) y=(y+1)%MAXN;
if(!hs[y]) return true;
return false;
}
void left()
{
int t=a[mid];
for(int i=mid;i>1;i--) a[i]=a[i-1];
a[1]=t;
}
void right()
{
int t=a[mid];
for(int i=mid;i<n;i++) a[i]=a[i+1];
a[n]=t;
}
bool check()
{
for (int i=1;i<n;i++) if (a[i]>a[i+1]) return 0;
return 1;
}
void bfs()
{
if (hash(state[1])) n=n;
head=0;tail=1;
do
{
head=head%1000001+1;//循环队列
for (int i=1;i<=n;i++) a[i]=state[head][i];//a用来记录操作的状态
left();//往左
if (hash(a))//如果之前没搜过就可以进队
{
tail=tail%1000001+1;
for(int i=1;i<=n;i++) state[tail][i]=a[i];
bs[tail]=bs[head]+1;//记录答案
}
if (check()) {ok=1;printf("%d",bs[tail]);return;}
for (int i=1;i<=n;i++) a[i]=state[head][i];
right();//往右
if (hash(a))
{
tail=tail%1000001+1;
for(int i=1;i<=n;i++) state[tail][i]=a[i];
bs[tail]=bs[head]+1;
}
if (check()) {ok=1;printf("%d",bs[tail]);return;}
}
while (head!=tail);
}
int main()
{
scanf("%d",&n);mid=(n+1)>>1;
for (int i=1;i<=n;i++) scanf("%d",&state[1][i]),state[1][i]-=159;
bfs();
if(!ok)printf("No Answer");
}