• kuangbin专题——简单搜索


    A - 棋盘问题

     POJ - 1321 

    题意  

    在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。

    解法:n皇后的变形,注意放的位置不一定,并不是每一行都要放,计个step,然后dfs每一个点时,记得回溯上去处理一下,把vis[i]置为0,step--即可,然后处理完此次结束后,dfs(x+1),处理下一位;

    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++)
    #define per(i,j,k) for(int i=(int)k;i>=(int)j;i--)
    int step,ans,n,k; 
    char mp[20][20];
    bool vis[20];
    void dfs(int x){
         if(step==k){
         ans++;
         return ;
         }
         if(x>=n)return ;
         for(int i=0;i<n;i++){
         if(!vis[i]&&mp[x][i]=='#'){
         step++;
         vis[i]=1;
         dfs(x+1);
         vis[i]=0;
         step--;
         }
         }
         dfs(x+1);
    }
    int main(){
        while(~scanf("%d %d",&n,&k)){
        memset(vis,0,sizeof vis);
        if(n+k<0)break;
        rep(i,0,n-1){
        scanf("%s",mp[i]);
        }
        ans=step=0;
        dfs(0);
        printf("%d
    ",ans);
        
        }
        return 0;    
    }
    View Code

    B - Dungeon Master

     POJ - 2251

    题意:就是个三维迷宫,直接广搜即可,用一个方向数组

    #include<bits/stdc++.h>
    #include<queue>
    #include<cstring>
    using namespace std;
    #define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++)
    #define per(i,j,k) for(int i=(int)k;i>=(int)j;i--)
    #define pb push_back
    #define fi first
    #define se second
    typedef long long ll;
    typedef unsigned long long ull;
    typedef long double ldb;
    const int maxn=1e5+5;
    bool isprime[maxn];
    void makeprime(){
         memset(isprime,true,sizeof isprime);
         isprime[1]=0;
         for(int i=2;i*i<=maxn;i++){
         if(isprime[i]==0)continue;
         for(int j=i*2;j<=maxn;j+=i){
         isprime[j]=0;
         }
         }
    //     rep(i,1,maxn){
    //     cout<<i<<" "<<isprime[i]<<endl;
    //     }
    }
    struct point{int num,step;};
    int ans,p,q;
    bool vis[maxn]; 
    bool  bfs(){
          memset(vis,0,sizeof vis);
         vis[p]=1;
         point tmp,next;
         tmp.num=p,tmp.step=0;
         queue<point>Q;
         Q.push(tmp);
         while(!Q.empty()){
         tmp=Q.front();
         Q.pop();
         vis[tmp.num]=1;
         if(tmp.num==q){
         ans=tmp.step;
         return true;
         } 
         int t=tmp.num;
         for(int i=0;i<4;i++){
         for(int j=0;j<=9;j++){
         t=tmp.num;
         if(i==0){
         t-=t%10;
         t+=j;
         }
         else if(i==1){
         t-=t%100/10*10;
         t+=j*10;
         }
         else if(i==2){
         t-=t%1000/100*100;
         t+=j*100;
         }
         else if(i==3){
         t-=t%10000/1000*1000;
         t+=j*1000;
         }
         if(t==tmp.num||t<1000||vis[t]||!isprime[t])continue;
         next.num=t,next.step=tmp.step+1;
         vis[t]=1;
         Q.push(next);
         }
         }
         
         }
         return false;
    }
    int main(){
        makeprime();
        int cas;
        scanf("%d",&cas);
        while(cas--){
        memset(vis,0,sizeof vis);
        scanf("%d %d",&p,&q);
        ans=0;
        if(bfs())printf("%d
    ",ans);
        else printf("Impossible
    "); 
        
        }
        return 0;
    }
    View Code

     题意:给你n和m,问几步能走到,直接广搜即可

    #include<cstdio>
    #include<queue>
    #include<cstring>
    using namespace std;
    #define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++)
    #define per(i,j,k) for(int i=(int)k;i>=(int)j;i--)
    #define pb push_back
    #define fi first
    #define se second
    #define check(x) (x<=N&&x>=0)
    typedef long long ll;
    typedef unsigned long long ull;
    typedef long double ldb;
    const int N=1e5+5;
    bool vis[N];
    int step[N];
    int n,k;
    void bfs(){
         queue<int>Q;
         vis[n]=1;
         step[n]=0;
         Q.push(n);
         while(!Q.empty()){
         int s=Q.front();
         if(s==k)return ;
         Q.pop();
         if(check(s+1)&&!vis[s+1]){
         vis[s+1]=1;
         step[s+1]=step[s]+1;
         Q.push(s+1);
         }
         if(check(s-1)&&!vis[s-1]){
         vis[s-1]=1;
         step[s-1]=step[s]+1;
         Q.push(s-1);
         }
         if(check(s<<1)&&!vis[s<<1]){
         vis[s<<1]=1;
         step[s<<1]=step[s]+1;
         Q.push(s<<1);
         }
         } 
    }
    int main(){
        while(~scanf("%d%d",&n,&k)){
        if(n>=k){
        printf("%d
    ",n-k);
        }
        else {
        memset(vis,false,sizeof vis);
        memset(step,0,sizeof step);
        bfs();
        printf("%d
    ",step[k]);
        }    
        }
    
        return 0;
    }
    View Code

    D - Fliptile(学到许多)

     POJ - 3279 

     题意: 给你一个01网格图,问你怎么按这些点,使得网格图全部置为0,找出字典序最小的方案;

    解法: 这题用到二进制思想,解法就是枚举第一行的按键,然后剩下的每一行都可以由上一行递推而来;

    递推公式为:press[i][j]=(mp[i-1][j]+press[i-1][j]+press[i-1][j+1]+press[i-2][j]+press[i-1][j-1])&1;

    最后判断一下情况是否符合,即最后一行按键是否能全部熄灭,

    这里我犯了一个错误,就是判断最后一行时没有按照递推公式算导致错误;

    然后枚举第一行的按键用到了二进制,即枚举0<i<(1<<m),表示有m位二进制数,然后用位运算截取每一位数,即为 press[1][j]=(i>>(m-j))&1;

    over

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std; 
    int mp[20][20],ans[20][20],press[20][20];
    int n,m;
    const int inf=0x3f3f3f3f;
    int guess(){
    
        for(int i=2;i<=n;i++){
        for(int j=1;j<=m;j++){
        press[i][j]=(mp[i-1][j]+press[i-1][j]+press[i-1][j+1]+press[i-2][j]+press[i-1][j-1])&1;
        }
        }
        for(int j=1;j<=m;j++){
        if((press[n][j]+mp[n][j]+
        press[n-1][j]+press[n][j-1]+press[n][j+1])&1!=0)
        return inf;
        }
        
        int cnt=0;    
        for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
        cnt+=press[i][j];
        }
        }
    
        return cnt;
    }
    int main(){
        
        while(~scanf("%d%d",&n,&m)){
        memset(mp,0,sizeof mp);
        memset(ans,0,sizeof ans);
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        scanf("%d",&mp[i][j]);
        int res=inf;
        for(int i=0;i<(1<<m);i++){
        memset(press,0,sizeof press);
        int test=1;
        for(int j=1;j<=m;j++){
        press[1][j]=(i>>(m-j))&1;
        }
    //    cout<<"test:"<<i<<" "<<guess()<<endl;
    //    for(int i=1;i<=n;i++)
    //    for(int j=1;j<=m;j++)
    //    printf("%d%c",press[i][j],j==m?'
    ':' ');
        
        int sum=guess();
        if(res>sum){
        res=sum;
        memcpy(ans,press,sizeof press);
        }
        }    
        if(res==inf)printf("IMPOSSIBLE
    ");
        else {
    //        cout<<"test:"<<endl;
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        printf("%d%c",ans[i][j],j==m?'
    ':' ');
    
        }
        }
        return 0;
    }
    View Code

    E - Find The Multiple

     POJ - 1426 

    题意:就是给你一个数,让你找它的一个只含01倍数的十进制数,

    解法:直接深搜,但开始T了一发,没有做好剪树枝

    计一个flag,如果搜到目标就停止;这样就能过了;

    #include<cstdio>
    using namespace std;
    #define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++)
    #define per(i,j,k) for(int i=(int)k;i>=(int)j;i--)
    #define pb push_back
    typedef long long ll;
    typedef unsigned long long ull;
    int n,flag;
    ull ans;
    void dfs(ull x,int step){
         if(flag)return ;
         if(x%n==0){
         flag=1;
         ans=x;
         return ;
         }
         if(step==19)return ;
         dfs(x*10+1,step+1);
         dfs(x*10,step+1);
    }
    int main(){
    //    cout<<1000000000000000110%6<<endl;
        while(~scanf("%d",&n),n){
        ans=0,flag=0;
        dfs(1*1ll,1);
        printf("%lld
    ",ans);
        }
        return 0;    
    }
    View Code

    F - Prime Path

     POJ - 3126 

    题意:就是给你两个素数,问你移动几步,使得由p走到q,而且每次移动只能变为素数,问你要变换几步;

    解法:直接广搜即可;注意枚举每一位的情况;

    #include<bits/stdc++.h>
    #include<queue>
    #include<cstring>
    using namespace std;
    #define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++)
    #define per(i,j,k) for(int i=(int)k;i>=(int)j;i--)
    #define pb push_back
    #define fi first
    #define se second
    typedef long long ll;
    typedef unsigned long long ull;
    typedef long double ldb;
    const int maxn=1e5+5;
    bool isprime[maxn];
    void makeprime(){
         memset(isprime,true,sizeof isprime);
         isprime[1]=0;
         for(int i=2;i*i<=maxn;i++){
         if(isprime[i]==0)continue;
         for(int j=i*2;j<=maxn;j+=i){
         isprime[j]=0;
         }
         }
    //     rep(i,1,maxn){
    //     cout<<i<<" "<<isprime[i]<<endl;
    //     }
    }
    struct point{int num,step;};
    int ans,p,q;
    bool vis[maxn]; 
    bool  bfs(){
          memset(vis,0,sizeof vis);
         vis[p]=1;
         point tmp,next;
         tmp.num=p,tmp.step=0;
         queue<point>Q;
         Q.push(tmp);
         while(!Q.empty()){
         tmp=Q.front();
         Q.pop();
         vis[tmp.num]=1;
         if(tmp.num==q){
         ans=tmp.step;
         return true;
         } 
         int t=tmp.num;
         for(int i=0;i<4;i++){
         for(int j=0;j<=9;j++){
         t=tmp.num;
         if(i==0){
         t-=t%10;
         t+=j;
         }
         else if(i==1){
         t-=t%100/10*10;
         t+=j*10;
         }
         else if(i==2){
         t-=t%1000/100*100;
         t+=j*100;
         }
         else if(i==3){
         t-=t%10000/1000*1000;
         t+=j*1000;
         }
         if(t==tmp.num||t<1000||vis[t]||!isprime[t])continue;
         next.num=t,next.step=tmp.step+1;
         vis[t]=1;
         Q.push(next);
         }
         }
         
         }
         return false;
    }
    int main(){
        makeprime();
        int cas;
        scanf("%d",&cas);
        while(cas--){
        memset(vis,0,sizeof vis);
        scanf("%d %d",&p,&q);
        ans=0;
        if(bfs())printf("%d
    ",ans);
        else printf("Impossible
    "); 
        
        }
        return 0;
    }
    View Code

    G - Shuffle'm Up

     POJ - 3087 

    题意:就是给你两堆牌,问你怎么洗才能洗到目标状态,如果洗不到,输出-1;

    解法:模拟洗牌的过程,如果洗到初始的状态,说明洗不到,

    这里我犯了一个错误,就是在在下标里面写位运算会出错,也不知tmp[i*2]=s2[i];道为什么;

    tmp[i*2]=s2[i];  写成tmp【i>.>1】就不对了

    #include<iostream>
    #include<string>
    #define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++)
    #define per(i,j,k) for(int i=(int)k;i>=(int)j;i--)
    using namespace std;
    typedef long long ll;
    string tmp,s1,s2,s12,goal;
    int step,n,ans;
    void bfs(){
    
         s1=tmp.substr(0,n);
         s2=tmp.substr(n,n);
         for(int i=0;i<n;i++){
         tmp[i*2]=s2[i];
         tmp[i*2+1]=s1[i];
         }
         step++;
         if(tmp.compare(goal)==0){
         ans=step;
         return ;
         }
           if(tmp.compare(s12)==0){
           ans=-1;
           return ;
           }
         bfs();  
    }
    int main(){
        int t,cas=1;
    //    scanf("%d",&t);
        cin>>t;
        while(t--){
    //    scanf("%d",&n);
        cin>>n>>s1>>s2>>goal;
        tmp=s1+s2;
        s12=tmp;
        ans=step=0;
        bfs();
        printf("%d %d
    ",cas++,ans);
        }
        return 0;
    }
    View Code

    待更新;

    PS:还是太菜了,要坚持刷题,写博客;

    想的太多,做的太少;
  • 相关阅读:
    MySQL数据库的登陆
    Mysql 数据库的介绍
    前台后台数据的传递
    header函数
    循环结构
    流程控制
    JS与PHP数组操作的不同
    HDU 3265/POJ 3832 Posters(扫描线+线段树)(2009 Asia Ningbo Regional)
    HDU 3264/POJ 3831 Open-air shopping malls(计算几何+二分)(2009 Asia Ningbo Regional)
    HDU 3262/POJ 3829 Seat taking up is tough(模拟+搜索)(2009 Asia Ningbo Regional)
  • 原文地址:https://www.cnblogs.com/littlerita/p/12305990.html
Copyright © 2020-2023  润新知