• 2017福建夏令营Day3(搜索)


    走出迷宫(maze)

    【题目描述】 当你站在一个迷宫里的时候,往往会被错综复杂的道路弄得失去方向感,如果你能 得到迷宫地图,事情就会变得非常简单。 假设你已经得到了一个 n × m 的迷宫的图纸,请你找出从起点到出口的最短路。

    【输入格式】 从文件 maze.in 中读入数据。 第一行是两个整数 n 和 m,表示迷宫的行数和列数。 接下来 n 行,每行一个长为 m 的字符串,表示整个迷宫的布局。字符. 表示空地, # 表示墙,S 表示起点,T 表示出口。

    【输出格式】 输出到文件 maze.out 中。 输出从起点到出口最少需要走的步数。

    【样例 1 输入】 3 5 T..## #.#.S #...#

    【样例 1 输出】 7

    【子任务】 对于 40% 的数据,保证 1 ≤ n, m ≤ 5; 对于另外 20% 的数据,地图中不包含字符 #; 对于 100% 的数据,保证 1 ≤ n, m ≤ 100,保证从起点出发一定能到达出口。

    题解

    搜索

    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    char ch[105];
    int n,m,ans=1e9+7;
    int a[105][105],vis[105][105],way[105][105];
    int dx[5]={0,0,1,0,-1},dy[5]={0,1,0,-1,0};
    int xx,yy;
    inline void dfs(int x,int y,int t)
    {
        if(abs(xx-x)+abs(yy-y)+t>=ans)    return;
        if(a[x][y]==2)
        {
            ans=std::min(ans,t);
            return;
        }
        way[x][y]=std::min(way[x][y],t);
        vis[x][y]=1;
        for(int i=1;i<=4;i++)
        {
            int nx=x+dx[i],ny=y+dy[i];
            if(nx>0 && nx<=n && ny>0 && ny<=m && !vis[nx][ny] && a[nx][ny]!=1 && t+1<way[nx][ny])
                dfs(nx,ny,t+1);
        }
        vis[x][y]=0;
    }
    int main()
    {
        freopen("maze.in","r",stdin);
        freopen("maze.out","w",stdout);
        int x,y;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",ch+1);
            for(int j=1;j<=m;j++)
            {
                if(ch[j]=='.')        a[i][j]=0;
                if(ch[j]=='#')        a[i][j]=1;
                if(ch[j]=='S')        x=i,y=j,a[i][j]=3;
                if(ch[j]=='T')    a[i][j]=2,xx=i,yy=j;
                way[i][j]=1e9+7;
            }
        }
        dfs(x,y,0);
        printf("%d
    ",ans);
        return 0;
    }

    标签

    深搜

    因数游戏(fac)

    【题目描述】 有 T 组询问,每组询问给定 2 个数 a, b,问从 a 变到 b 最少需要多少步,每次我们 可以把 a 加上它的一个因数或者减去它的一个因数。比如,6 可以变成 5, 7, 4, 8, 3, 9, 12。 特别地,如果步数 > 6 的话,输出 CalcFailed

    【输入格式】 从文件 fac.in 中读入数据。 输入有多组测试数据。第一行 T 表示测试数据的个数。 接下来 T 行,每行两个整数来表示 a, b。

    【输出格式】 输出到文件 fac.out 中。 输出 T 行,表示答案

    【样例 1 输入】 3 18 11 4 4 1 100

    【样例 1 输出】 2 0 CalcFailed

    【子任务】 对于 20% 的数据,答案 ≤ 2; 对于 40% 的数据,答案 ≤ 3; 对于 60% 的数据,答案 ≤ 4; 对于 80% 的数据,没有 CalcFailed; 对于 100% 的数据,1 ≤ T ≤ 10, 1 ≤ a, b ≤ 108。

    题解

    70分
    若x可以一步变成y,y一定可以一步变成x
    设x=ka(a为当前因数)
    ka+a=y,y=(k+1)a,y-a=x;
    因此我们可以从a,b同时开始双向搜索3层,用hash判断是否出现过,出现过就可以输出答案
    100分
    70分基础上搜索因数可以用Miller-Rabin+Rho
    即可过

    hash代码用的是链表维护

    也可以用set

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #define mod 5826451
    using namespace std;
    struct edge{
        int num,next;
    }g[15000005],g2[15000005];
    int head[5826452],head2[5826452];
    int h1,t1,h2,t2,tot,t,n,m,ans,tot2;
    int q[15000005],q2[15000005];
    bool fd(int x){
        int qaq=x%mod;
        for(int i=head[qaq];i;i=g[i].next)if(x==g[i].num)return true;
        return false;
    }
    bool fd2(int x){
        int qaq=x%mod;
        for(int i=head2[qaq];i;i=g2[i].next)if(x==g2[i].num)return true;
        return false;
    }
    void ins(int x){g[++tot].next=head[x%mod];head[x%mod]=tot;g[tot].num=x;}
    void ins2(int x){g2[++tot2].next=head2[x%mod];head2[x%mod]=tot2;g2[tot2].num=x;}
    int main(){
        freopen("fac.in","r",stdin);
        freopen("fac.out","w",stdout);
        scanf("%d",&t);
        for(int tt=1;tt<=t;tt++){
            scanf("%d%d",&n,&m);
            memset(head,0,sizeof(head));
            memset(head2,0,sizeof(head2));
            tot=ans=tot2=0;
            bool find=false;
            int now=1;h1=t1=h2=t2=1;
            q[h1]=n,q2[h2]=m;ins2(n);ins(m);if(n==m)find=true;
            for(int i=1;i<=6;i++){
                if(find)break;
                now=!now;
                if(!now){
                    int tmp=t1;
                    for(int j=h1;j<=t1;j++){
                        for(int k=1;k<=sqrt(q[j]);k++){
                            if(q[j]%k==0){
                                if(!fd2(q[j]+k)){
                                    q[++tmp]=q[j]+k;
                                    if(!fd(q[j]+k))ins2(q[j]+k);else {find=true;ans=i;break;}
                                }
                                if(q[j]-k&&!fd2(q[j]-k)){
                                    q[++tmp]=q[j]-k;
                                    if(!fd(q[j]-k))ins2(q[j]-k);else {find=true;ans=i;break;}
                                }
                                if(q[j]!=1&&!fd2(q[j]+q[j]/k)){
                                    q[++tmp]=q[j]+q[j]/k;
                                    if(!fd(q[j]+q[j]/k))ins2(q[j]+q[j]/k);else {find=true;ans=i;break;}
                                }
                                if(q[j]-q[j]/k&&!fd2(q[j]-q[j]/k)){
                                    q[++tmp]=q[j]-q[j]/k;
                                    if(!fd(q[j]-q[j]/k))ins2(q[j]-q[j]/k);else {find=true;ans=i;break;}
                                }
                            }
                        }
                        if(find)break;
                    }
                    h1=t1+1,t1=tmp;
                }else{
                    int tmp=t2;
                    for(int j=h2;j<=t2;j++){
                        for(int k=1;k<=sqrt(q2[j]);k++){
                            if(q2[j]%k==0){
                                if(!fd(q2[j]+k)){
                                    q2[++tmp]=q2[j]+k;
                                    if(!fd2(q2[j]+k))ins(q2[j]+k);else {find=true;ans=i;break;}
                                }
                                if(q2[j]-k&&!fd(q2[j]-k)){
                                    q2[++tmp]=q2[j]-k;
                                    if(!fd2(q2[j]-k))ins(q2[j]-k);else {find=true;ans=i;break;}    
                                }
                                if(q2[j]!=1&&!fd(q2[j]+q2[j]/k)){
                                    q2[++tmp]=q2[j]+q2[j]/k;
                                    if(!fd2(q2[j]+q2[j]/k))ins(q2[j]+q2[j]/k);else {find=true;ans=i;break;}    
                                }
                                if(q2[j]-q2[j]/k&&!fd(q2[j]-q2[j]/k)){
                                    q2[++tmp]=q2[j]-q2[j]/k;
                                    if(!fd2(q2[j]-q2[j]/k))ins(q2[j]-q2[j]/k);else {find=true;ans=i;break;}
                                }
                            }
                        }
                        if(find)break;
                    }
                    h2=t2+1,t2=tmp;
                }
            }
            if(find)printf("%d
    ",ans);
            else puts("CalcFailed");
        }    
        fclose(stdin);
        fclose(stdout);
    }

    标签

    双向bfs

    十五数码(fifteen)

    【题目描述】 给出起始顺序,要求通过 0 的移动(与上下左右交换),排成以下顺序: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 【输入格式】 从文件 fifteen.in 中读入数据。 4 个数一行,共 4 行 16 个数。

    【输出格式】 输出到文件 fifteen.out 中。 输出最少移动次数。如. 果. 无. 解. 输. 出. No。

    【样例 1 输入】 1 2 3 4 5 6 7 8 9 10 11 12 13 14 0 15

    【样例 1 输出】 1

    【样例 2 输入】 1 11 3 8 5 7 0 2 9 13 4 12 6 10 14 15

    【样例 2 输出】 33

    【子任务】 对于 20% 的数据,保证有解并且 Ans ≤ 12 对于 50% 的数据,保证有解并且 Ans ≤ 28 存在 10% 的数据无解 对于 100% 的数据,如果有解,Ans ≤ 50

    题解
    50分的A*
    设置最大深度dep
    当前为g(i),估价函数设为每个数与目标曼哈顿距离,若g(i)+h(i)<=dep就继续搜,之后再加大深度
    优化记录上次状态不走回头路
    若h(i)为0即可以输出答案

    100分

    位运算. i ≫ 2, i & 3

    #define abs(x) (x>=0?x:-(x))

    一些经常调用的小函数拿去 define 掉, 因为声明函数栈空间花 时间。

    特判无解情况

    二维数组改成一维,a[4][4] → a[16]

    减少估价函数的计算量. 本题中的 h(n) 满足加法运算

    调整 udlr 的顺序, 改变搜索序

    把起始局面和目标局面对掉

    反正这种想法就是脑洞很大的才想的出来

    50分

    #include <cstdio>  
    #include <cstring>  
    #include <cmath>  
    #include <algorithm>
    #include <iostream>
    const int M = 4;
    void swap(int*a,int*b){int tmp; tmp = *a; *a = *b; *b = tmp;}  
    int move[4][2]={{-1,0},{0,-1},{0,1},{1,0}}, map[M][M], map2[M*M], to[16][2]= {{3,3},{0,0},{0,1}, {0,2},{0,3}, {1,0},{1,1}, {1,2}, {1,3},{2,0}, {2,1}, {2,2},{2,3},{3,0},{3,1},{3,2}};
    int limit, flag = 0, length = 0;
    int lunar(int a[][M])
    {  
        int cost=0;  
        for(int i=0; i<M; i++)  
            for(int j=0; j<M; j++)  
            {  
                int w = map[i][j];  
                cost += abs(i-to[w][0]) + abs(j-to[w][1]);  
            }  
        return cost;  
    }  
    void dfs(int sx,int sy,int len,int l)
    {  
        int nx,ny;  
        if(flag) return;  
        int ma = lunar(map);  
        if(len == limit)  
        {  
            if(ma == 0) 
            {  
                flag=1; length=len;  
                return;  
            }  
            else return;
        }  
        else if(len<limit && ma==0)  
        {  
            flag=1; length=len;  
            return;  
        }  
        for(int i=0; i<4; i++)  
        {  
            if(i + l == 3 && len>0) continue;      
            nx=sx + move[i][0]; ny = sy + move[i][1];  
            if(0<=nx&&nx<M && 0<=ny&&ny<M) 
            {  
                swap(&map[sx][sy],&map[nx][ny]);  
                int p=lunar(map);   
                if(p+len<=limit&&!flag)  
                {  
                    dfs(nx,ny,len+1,i); 
                    if(flag) return;  
                }  
                swap(&map[sx][sy], &map[nx][ny]);
            }  
        } 
        return;
    }  
    int main()  
    {  
        freopen("fifteen.in","r",stdin);
        freopen("fifteen.out","w",stdout);
        int sx, sy;   
        for(int i=0; i<M * M; i++) 
        {  
            scanf("%d", &map2[i]);  
            if(map2[i]==0)  
            {   
                map[i/M][i%M] = 0;  
                sx = i/M; sy = i%M;  
            }  
            else  
                map[i/M][i%M] = map2[i];   
        }                                      
        limit = lunar(map);  
        while(!flag && length<=50) 
        {  
            dfs(sx, sy, 0, 0);  
            if(!flag) limit++;   
        }  
        if(flag) printf("%d
    ", length); 
        else printf("No
    ");   
        return 0;  
    }  

    标签

    A*搜索,细节

  • 相关阅读:
    解决方案
    项目管理
    项目管理
    产品经理
    产品经理
    产品经理
    产品经理
    vue学习面向对象,在项目中怎么用呢?
    vue表单验证不通过,依然能执行点击事件里面的代码?
    vue中js文件中export常见方法及使用
  • 原文地址:https://www.cnblogs.com/Droyal/p/7418319.html
Copyright © 2020-2023  润新知