这两天学了A*算法和双搜,A*在补充到上一篇总结中去了,A*的难度还可以接受,毕竟现阶段只是用来优化时间的。而双搜。。。我以为有了双搜之后做题会很简单,但没想到做双搜的题那么难,打起代码来十分烫手,更多的是一些又来解决问题的方法不会,还需要大量练习。另外,这种一道题看一天还看不会的感觉真让我着迷,嘿嘿嘿(已疯)。
hdu1401
一开始不知道是一个棋子一个棋子的动还是全都一块动,搜了题解后额。。是一块一块的动(突然感觉自己好智障啊),起始和终点都知道,用双广搜,对点进行排序更有利于搜索,难点是如何模拟和判断点能不能进行各方向移动。自己眼又瞎了,q2.pop();放错了位置,哎,又是被自己蠢哭的一天。。。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<map>
#include<cmath>
#include<vector>
#include<queue>
#include<list>
#include<stack>
#include<set>
#include<ctime>
#define ll long long
#define CHECK(x,y,z) (x>=0&&x<a&&y>=0&&y<b&&z>=0&&z<c&&!(vis[x][y][z])&&val[x][y][z])
//#include<bits/stdc++.h>
using namespace std;
char vis[8][8][8][8][8][8][8][8];
int dir[4][3]={{-1,0},{0,-1},{1,0},{0,1}};
struct zuob{
int x;int y;
};
struct Node{
zuob p[4];
int step;
};
Node start,endd,ss;
bool cmp(const zuob& a,const zuob& b){
if(a.x==b.x)
return a.y<b.y;
else return a.x<b.x;
}
int judge(Node& s,int i,int j,int flag){
if(flag==1){
if(s.step>=4)
return 0;
s.step++;
}
s.p[i].x+=dir[j][0];
s.p[i].y+=dir[j][1];
if(s.p[i].x>=0&&s.p[i].x<8&&s.p[i].y>=0&&s.p[i].y<8){
int k;
for(k=0;k<4;k++){
if(i!=k){
if(s.p[i].x==s.p[k].x&&s.p[i].y==s.p[k].y)
if(flag==1){
return judge(s,i,j,0);
}//如果移动后的该点与另外的点重合了,就判断一下再往这个方向走一步是否还会有棋子,
//如果没有就相当于这棋子跨过去了那个棋子,如果还有就说明该棋子不能往这方向走
else return 0;
}
}
if(k>=4){
// cout<<"yes"<<endl;
sort(s.p,s.p+4,cmp);//没有障碍就重新排序
return 1;
}
}
return 0;
}
int bfs(){
queue<Node>q1,q2;
q1.push(start);q2.push(endd);
vis[start.p[0].x][start.p[0].y][start.p[1].x][start.p[1].y][start.p[2].x][start.p[2].y][start.p[3].x][start.p[3].y]='1';
vis[endd.p[0].x][endd.p[0].y][endd.p[1].x][endd.p[1].y][endd.p[2].x][endd.p[2].y][endd.p[3].x][endd.p[3].y]='2';
while(!q1.empty()||!q2.empty()){
if(!q1.empty()){
// cout<<q1.front().p[0].x<<q1.front().p[0].y<<q1.front().p[1].x<<q1.front().p[1].y<<q1.front().p[2].x<<q1.front().p[2].y<<q1.front().p[3].x<<q1.front().p[3].y<<endl;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
ss=q1.front();
if(judge(ss,i,j,1)){
if(vis[ss.p[0].x][ss.p[0].y][ss.p[1].x][ss.p[1].y][ss.p[2].x][ss.p[2].y][ss.p[3].x][ss.p[3].y]=='1')
continue;
if(vis[ss.p[0].x][ss.p[0].y][ss.p[1].x][ss.p[1].y][ss.p[2].x][ss.p[2].y][ss.p[3].x][ss.p[3].y]=='2')//和q2碰面
return 1;
q1.push(ss);
vis[ss.p[0].x][ss.p[0].y][ss.p[1].x][ss.p[1].y][ss.p[2].x][ss.p[2].y][ss.p[3].x][ss.p[3].y]='1';
}
}
}
q1.pop();
}
if(!q2.empty()){
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
ss=q2.front();
if(judge(ss,i,j,1)){
if(vis[ss.p[0].x][ss.p[0].y][ss.p[1].x][ss.p[1].y][ss.p[2].x][ss.p[2].y][ss.p[3].x][ss.p[3].y]=='2')
continue;
if(vis[ss.p[0].x][ss.p[0].y][ss.p[1].x][ss.p[1].y][ss.p[2].x][ss.p[2].y][ss.p[3].x][ss.p[3].y]=='1')//和q1碰面
return 1;
q2.push(ss);
vis[ss.p[0].x][ss.p[0].y][ss.p[1].x][ss.p[1].y][ss.p[2].x][ss.p[2].y][ss.p[3].x][ss.p[3].y]='2';
}
}
}
q2.pop();
}
}
return 0;
}
int main(){
//freopen("in.txt","r",stdin);
while(cin>>start.p[0].x>>start.p[0].y){
start.p[0].x--;start.p[0].y--;
for(int i=1;i<4;i++){
cin>>start.p[i].x>>start.p[i].y;
start.p[i].x--;start.p[i].y--;
}
for(int i=0;i<4;i++){
cin>>endd.p[i].x>>endd.p[i].y;
endd.p[i].x--;endd.p[i].y--;
}
start.step=0;endd.step=0;
sort(start.p,start.p+4,cmp);
sort(endd.p,endd.p+4,cmp);
memset(vis,'0',sizeof vis);
if(bfs()) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
/* jieshu=clock();
cout<<endl;
cout<<(double)(jieshu-kaishi)/CLOCKS_PER_SEC<<endl;*/
return 0;
}
hdu3567
这道题。。。属实给我弄懵逼了,一开始还以为就是把单搜变为广搜就完了,事实上要难的多,还要考虑字典序的问题,看题解又扯上了什么四进制。。大体思路了解了,但还是有很多不是很清楚的,先贴上抄的别人的代码,等对搜索和其他基础知识掌握的更加牢固后再回来看吧。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<map>
#include<cmath>
#include<vector>
#include<queue>
#include<list>
#include<stack>
#include<set>
#include<ctime>
#define ll long long
#define CHECK(x,y,z) (x>=0&&x<a&&y>=0&&y<b&&z>=0&&z<c&&!(vis[x][y][z])&&val[x][y][z])
//#include<bits/stdc++.h>
using namespace std;
const int maxx=4e5+10;
const int INF=1e8;
int fact[9]={1,1,2,6,24,120,720,5040,40320};
int dir[4][2]={{1,0},{0,-1},{0,1},{-1,0}};
char d[10]={"dlru"};
ll dd[2][4]={{0,1,2,3},{3,2,1,0}};
int vis[2][maxx],ti,minans;
char ans[maxx],get[maxx];
ll c[2][maxx];
ll mm[30];
struct node{
int f[3][3];
int x,y;
int g,flag,hash_num;ll path;
};
int get_hash(node e){//康拓展开
int a[9],k=0,ans=0;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++)
a[k++]=e.f[i][j];
}
for(int i=0;i<9;i++){
k=0;
for(int j=0;j<i;j++)
if(a[j]>a[i]) k++;
ans+=fact[i]*k;
}
return ans;
}
string getstr(ll c,int flag,int kk){//获得字符串
int str[100];int k=0;
for(int i=0;i<vis[flag][kk];i++){
str[k++]=c%4;//十进制转四进制
c=c/4;
}
string s="";
for(int i=k-1;i>=0;i--)
s+=d[str[i]];
return s;
}
void bfs(node e,node ee){
memset(vis,-1,sizeof(vis));
int k,xx,yy,dis[2];
dis[0]=dis[1]=0;
node a,b;
e.hash_num=get_hash(e);
e.g=0,e.flag=0;
e.path=0;
ee.hash_num=get_hash(ee);
ee.g=0,ee.flag=1;
ee.path=0;
vis[0][e.hash_num]=0;
vis[1][ee.hash_num]=0;
if(e.hash_num==ee.hash_num){printf("0\n\n");return;}
queue<node>q;
q.push(e);q.push(ee);
minans=INF;
ll str;
string res;
while(!q.empty()){
e=q.front();
q.pop();
for(int i=0;i<4;i++){
a=e;
a.x=e.x+dir[i][0];
a.y=e.y+dir[i][1];
if(a.x<0||a.y<0||a.x>=3||a.y>=3)continue;
swap(a.f[e.x][e.y],a.f[a.x][a.y]);
k=get_hash(a);
if(vis[e.flag][k]!=-1){
if(e.g+1>vis[e.flag][k]) continue;
else{
if(e.flag) str=dd[e.flag][i]*mm[e.g]+e.path;//为四进制做准备
else str=e.path*4+dd[e.flag][i];
if(c[e.flag][k]>str)
c[e.flag][k]=str;
}
}
else {
vis[e.flag][k]=e.g+1;
if(e.flag)c[e.flag][k]=dd[e.flag][i]*mm[e.g]+e.path;
else c[e.flag][k]=e.path*4+dd[e.flag][i];
}
a.hash_num=k;
a.g++;
a.path=c[e.flag][k];
if(vis[e.flag^1][k]!=-1){
string s=getstr(c[0][k],0,k)+getstr(c[1][k],1,k);
ti=s.length();//cout<<ti<<endl;
if(ti>minans){
cout<<minans<<endl;
cout<<res<<endl;
return;
}
if(ti<minans){
minans=ti;
res=s;
}
else {
if(res.compare(s)>0) res=s;
}
}
q.push(a);
}
}
}
void init(){
mm[0]=1;
for(int i=1;i<=30;i++)
mm[i]=mm[i-1]*4;
}
int main(){
init();
//freopen("in.txt","r",stdin);
int t,tt=1;
cin>>t;
char a[30],b[30];
while(t--){
cin>>a>>b;
int n=strlen(a);
node e,pp;
for(int i=0;i<n;i++){
if(a[i]=='X'){e.f[i/3][i%3]=0;e.x=i/3;e.y=i%3;}
else e.f[i/3][i%3]=a[i]-'0';
if(b[i]=='X'){pp.f[i/3][i%3]=0;pp.x=i/3;pp.y=i%3;}
else pp.f[i/3][i%3]=b[i]-'0';
}
printf("Case %d: ",tt++);
bfs(e,pp);
}
/* jieshu=clock();
cout<<endl;
cout<<(double)(jieshu-kaishi)/CLOCKS_PER_SEC<<endl;*/
return 0;
}
8.18来粘上ida的做法,也是看的题解,题解有一两句没用的,改了一下,说实话真挺难看懂的。。。至于上面的四进制方法,,额。。。我都不想再看了。。。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<iomanip>
#include<map>
#include<cmath>
#include<vector>
#include<queue>
#include<deque>
#include<list>
#include<stack>
#include<set>
#include<ctime>
#define ll long long
#define CHECK(x,y) (x>=0&&x<8&&y>=0&&y<8)
//#include<bits/stdc++.h>
using namespace std;
const ll maxx=1e9;
int dir[7][4]={
{1,0},
{0,-1},
{0,1},
{-1,0}
};
struct node{
int x,y;
}endd[10];
char s[10],d[4]={'d','l','r','u'},a[4][4];
int sx,sy,flag,ans[210],lim;
int h(){
int tmp=0;
for(int i=0;i<9;i++){
int x=i/3,y=i%3;
if(a[x][y]=='X') continue;
tmp+=abs(x-endd[a[x][y]-'0'].x)+abs(y-endd[a[x][y]-'0'].y);
}
return tmp;
}
int ida(int x,int y,int p,int cnt){
int bound;
int hv=h();
if(cnt+hv>lim) return cnt+hv;//排除掉错误答案,因为正确答案的步数是不会超过一开始的h()的
if(hv==0){flag=1;return cnt;}//到达目的地,回溯
for(int i=0;i<4;i++){
if(i==p) continue;//如果进行说明又回退了一步
int nx=x+dir[i][0];
int ny=y+dir[i][1];
if(nx<0||nx>=3||ny<0||ny>=3) continue;
swap(a[x][y],a[nx][ny]);
ans[cnt]=i;
bound=ida(nx,ny,3-i,cnt+1);//递归,p代表回退的那一步
if(flag) return bound;//将正确答案回溯
swap(a[x][y],a[nx][ny]);
}
return bound;
}
int main(){
// freopen("in.txt","r",stdin);
int t,cs=1;
cin>>t;
while(t--){
for(int i=0;i<9;i++){
cin>>s[i];
if(s[i]=='X'){
sx=i/3;sy=i%3;
}
a[i/3][i%3]=s[i];
}
for(int i=0;i<9;i++){
cin>>s[i];
if(s[i]=='X') continue;
endd[s[i]-'0'].x=i/3;
endd[s[i]-'0'].y=i%3;
}
lim=h();
flag=0;
while(!flag) lim=ida(sx,sy,-1,0);
printf("Case %d: %d\n",cs++,lim);
for(int i=0;i<lim;i++){
cout<<d[ans[i]];
}
cout<<endl;
}
return 0;
}