暑假学习记录7.27

142 篇文章 0 订阅
92 篇文章 0 订阅

        这两天学了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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

killer_queen4804

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值