搜索专题解题报告

1001:简单模拟题

#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<time.h>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<limits.h>
#include<set>
//#define ONLINE_JUDGE
#define eps 1e-8
#define INF 0x7fffffff
#define FOR(i,a) for((i)=0;i<(a);(i)++)
#define MEM(a) (memset((a),0,sizeof(a)))
#define sfs(a) scanf("%s",a)
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define pf(a) printf("%d\n",a)
#define pfI(a) printf("%I64d\n",a)
#define pfs(a) printf("%s\n",a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,num) scanf("%d%d%d",&a,&b,&num)
#define for1(i,a,b) for(int i=(a);i<b;i++)
#define for2(i,a,b) for(int i=(a);i<=b;i++)
#define for3(i,a,b)for(int i=(b);i>=a;i--)
#define MEM1(a) memset(a,0,sizeof(a))
#define MEM2(a) memset(a,-1,sizeof(a))
#define ll __int64
const double PI=acos(-1.0);
template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> inline T Min(T a,T b){return a<b?a:b;}
template<class T> inline T Max(T a,T b){return a>b?a:b;}
using namespace std;
int n,m,k;
#define M 500010
int main()
{
    while(sf(n)!=EOF){
        ll ans=1;
        n--;
        while(n--){
            ans = (ans+1)*2;
        }
        pfI(ans);
    }
return 0;
}



1002:按照题目要求,简单判断即可。

#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<time.h>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<limits.h>
#include<set>
//#define ONLINE_JUDGE
#define eps 1e-8
#define INF 0x7fffffff
#define FOR(i,a) for((i)=0;i<(a);(i)++)
#define MEM(a) (memset((a),0,sizeof(a)))
#define sfs(a) scanf("%s",a)
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define pf(a) printf("%d\n",a)
#define pfI(a) printf("%I64d\n",a)
#define pfs(a) printf("%s\n",a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,num) scanf("%d%d%d",&a,&b,&num)
#define for1(i,a,b) for(int i=(a);i<b;i++)
#define for2(i,a,b) for(int i=(a);i<=b;i++)
#define for3(i,a,b)for(int i=(b);i>=a;i--)
#define MEM1(a) memset(a,0,sizeof(a))
#define MEM2(a) memset(a,-1,sizeof(a))
#define ll __int64
const double PI=acos(-1.0);
template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> inline T Min(T a,T b){return a<b?a:b;}
template<class T> inline T Max(T a,T b){return a>b?a:b;}
using namespace std;
int n,m,k;
#define M 500010
char ch[55];
int main(){
    int t;
    sf(t);
    while(t--){
        sfs(ch);
        int len = strlen(ch);
        if(len<8 || len>16){
            printf("NO\n");
            continue;
        }
        int flag1=0,flag2=0,flag3=0,flag4=0;
        for(int i=0;i<len;i++){
            if(ch[i]>='A' && ch[i]<='Z')
                    flag1=1;
            else if(ch[i]>='a' && ch[i]<='z')
                flag2=1;
            else if(ch[i]>='0' && ch[i]<='9')
                flag3=1;
            else
                flag4=1;
        }
        if(flag1+flag2+flag3+flag4>=3){
            printf("YES\n");
        }else
            printf("NO\n");
    }
return 0;
}



1003:原题链接
hdu1241
题目就是求‘@’的联通子块的数目,联通的条件是上下左右相邻或者在用一条对角线上相邻。直接DFS即可,从’@’符号开始,边搜索边记录搜索过的块。

#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<time.h>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<limits.h>
#include<set>
//#define ONLINE_JUDGE
#define eps 1e-8
#define INF 0x7fffffff
#define FOR(i,a) for((i)=0;i<(a);(i)++)
#define MEM(a) (memset((a),0,sizeof(a)))
#define sfs(a) scanf("%s",a)
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define pf(a) printf("%d\n",a)
#define pfI(a) printf("%I64d\n",a)
#define pfs(a) printf("%s\n",a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,num) scanf("%d%d%d",&a,&b,&num)
#define for1(i,a,b) for(int i=(a);i<b;i++)
#define for2(i,a,b) for(int i=(a);i<=b;i++)
#define for3(i,a,b)for(int i=(b);i>=a;i--)
#define MEM1(a) memset(a,0,sizeof(a))
#define MEM2(a) memset(a,-1,sizeof(a))
#define ll __int64
const double PI=acos(-1.0);
template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> inline T Min(T a,T b){return a<b?a:b;}
template<class T> inline T Max(T a,T b){return a>b?a:b;}
using namespace std;
int n,m,k;
#define M 500010
char mp[110][110];
int vis[110][110];
bool check(int x,int y){
    if(x<0 || x>=n || y<0 || y>=m || mp[x][y] == '*' || vis[x][y])
         return false;
    return true;
}
void dfs(int x,int y){
    if(vis[x][y]) return;
    vis[x][y]=1;
    if(check(x-1,y)) dfs(x-1,y);
    if(check(x+1,y)) dfs(x+1,y);
    if(check(x,y-1)) dfs(x,y-1);
    if(check(x,y+1)) dfs(x,y+1);
    if(check(x-1,y-1)) dfs(x-1,y-1);
    if(check(x-1,y+1)) dfs(x-1,y+1);
    if(check(x+1,y-1)) dfs(x+1,y-1);
    if(check(x+1,y+1)) dfs(x+1,y+1);
    return;
}
int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
//  freopen("out.txt", "w", stdout);
#endif
    while(sfd(n,m)!=EOF && n){
        for(int i=0;i<n;i++){
            sfs(mp[i]);
        }
        memset(vis,0,sizeof vis);
        int ans=0;
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(mp[i][j] == '@' && !vis[i][j]){
                    ans++;
                    dfs(i,j);
                }
            }
        }
        printf("%d\n",ans);
    }
return 0;
}

1004:原题链接
hdu1242

题目给出一个地图,‘#’代表不可走的位置,’.’代表可走的位置,’a’代表angel所在的位置,’r’代表angel朋友所在的位置,’x’代表该位置有个守卫。求angel朋友能否就出angel,如果能,输出需要的最短时间。我们注意,一个angel有好几个朋友,所以我们把angel当做起点,用bfs搜索,一旦搜到某个位置是angel朋友所在的位置,那么此时一定是最短的时间,输出该时间即可。

#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<time.h>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<limits.h>
#include<set>
//#define ONLINE_JUDGE
#define eps 1e-8
#define INF 0x7fffffff
#define FOR(i,a) for((i)=0;i<(a);(i)++)
#define MEM(a) (memset((a),0,sizeof(a)))
#define sfs(a) scanf("%s",a)
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define pf(a) printf("%d\n",a)
#define pfI(a) printf("%I64d\n",a)
#define pfs(a) printf("%s\n",a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,num) scanf("%d%d%d",&a,&b,&num)
#define for1(i,a,b) for(int i=(a);i<b;i++)
#define for2(i,a,b) for(int i=(a);i<=b;i++)
#define for3(i,a,b)for(int i=(b);i>=a;i--)
#define MEM1(a) memset(a,0,sizeof(a))
#define MEM2(a) memset(a,-1,sizeof(a))
#define ll __int64
const double PI=acos(-1.0);
template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> inline T Min(T a,T b){return a<b?a:b;}
template<class T> inline T Max(T a,T b){return a>b?a:b;}
using namespace std;
int n,m,k;
#define M 500010
char mp[210][210];
int vis[210][210];
struct Node{
    int x,y;
    int step;
};
bool check(int x,int y){ //判断边界的函数
    if(x<0 || x>=n || y<0 || y>=m || mp[x][y] == '#' || vis[x][y])
         return false;
    return true;
}
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
void bfs(int x,int y){
    queue<Node> q;
    memset(vis,0,sizeof vis);
    Node cur,next;
    cur.x = x;
    cur.y = y;
    cur.step = 0;
    vis[x][y] = 1;
    q.push(cur);
    int ans=-1;
    while(!q.empty()){
        cur = q.front();
        q.pop();
        for(int i=0;i<4;i++){
            next.x = cur.x+dir[i][0];
            next.y = cur.y+dir[i][1];
            if(!check(next.x,next.y)) continue;
            vis[next.x][next.y] = 1;
            if(mp[next.x][next.y] == '.'){ //'.'可走,需1个单位的时间
                next.step = cur.step+1;
                q.push(next);
            }else if(mp[next.x][next.y] == 'r'){ //'r'为终点
                next.step = cur.step+1;
                ans = next.step;
                break;
            }else if(mp[next.x][next.y] == 'x'){//'x'可走,走需要1个单位时间,杀死该位置守卫需要1个单位,共2个单位时间
                next.step = cur.step+2;
                q.push(next);
            }
        }
    }
    if(ans == -1) //如果ans==-1,说明Angel并不能到达她朋友所在的位置
        printf("Poor ANGEL has to stay in the prison all his life.\n");
    else
        printf("%d\n",ans);
}
int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
//  freopen("out.txt", "w", stdout);
#endif
    while(sfd(n,m)!=EOF){
        for(int i=0;i<n;i++){
            sfs(mp[i]);
        }
        int stx,sty;
        int flag=0;
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(mp[i][j] == 'a'){
                    stx = i;
                    sty = j;
                    flag=1;
                    break;
                }
            }
            if(flag) break;
        }
        bfs(stx,sty);
    }
return 0;
}



1005:原题链接
hdu1728
题意不难懂。我们注意题目中所求的是最少的拐弯数,这和到达某一个点所经过的最短步数是不一样的。在求最短步数时,如果某个点被访问过了,那第二次就不访问了。但是在求最少的拐弯数时,我们并不能这样做。原因如图:
图片源
图中从起点到终点标有两条路,它们的步数是一样的,但是蓝色的拐弯数少,如果代码中我们先通过红色那条路访问到了终点,那么蓝色就不能再次访问终点了,但是就本题来说,显然蓝色的路更优。
所以,点是可以被重复访问的。
那么我们应该怎么做,使得点可以被重复访问,但是又不至于使得一些无用的点入队列那?我们还是使用vis[i][j],但是此时,vis[i][j]代表到达(i,j)这个点时,所需要的最小拐弯数,如果有其他点到达该点时所经过的拐弯数大于vis[i][j],那么显然,该状态肯定不是最优的,将其舍弃即可。当然,还有种做法就是从一个点一直走,走到走不了为止,那样下一次就得拐弯了。

#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<time.h>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<limits.h>
#include<set>
//#define ONLINE_JUDGE
#define eps 1e-8
#define INF 0x7fffffff
#define FOR(i,a) for((i)=0;i<(a);(i)++)
#define MEM(a) (memset((a),0,sizeof(a)))
#define sfs(a) scanf("%s",a)
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define pf(a) printf("%d\n",a)
#define pfI(a) printf("%I64d\n",a)
#define pfs(a) printf("%s\n",a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,num) scanf("%d%d%d",&a,&b,&num)
#define for1(i,a,b) for(int i=(a);i<b;i++)
#define for2(i,a,b) for(int i=(a);i<=b;i++)
#define for3(i,a,b)for(int i=(b);i>=a;i--)
#define MEM1(a) memset(a,0,sizeof(a))
#define MEM2(a) memset(a,-1,sizeof(a))
#define ll __int64
const double PI=acos(-1.0);
template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> inline T Min(T a,T b){return a<b?a:b;}
template<class T> inline T Max(T a,T b){return a>b?a:b;}
using namespace std;
struct Loc {
    int x;
    int y;
    int step;               //记录行走到某个点时转过的弯
    int pre;                 //记录走到某个点的方式(直走,反向,左转或者右转)
};
int dir[4][2] = { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 } };
int sa, sb, ea, eb;
queue<Loc> q;
int m, n;
char map[110][110];            //记录一副地图
int vis[110][110];                //记录走到某个点时最小的转弯数目
int k;                                //最大允许转弯的次数
int flag;
void bfs() {
    for (int i = 0; i < 110; i++)
        for (int j = 0; j < 110; j++)
            vis[i][j] = INF;             //初始化转弯的次数(必定要大于题目允许的最大值)
    while (!q.empty())
        q.pop();
    Loc cur, next;
    cur.x = sa;
    cur.y = sb;
    cur.step = -1;
    cur.pre = -1;                                //初始化
    //cur.step=0;
    vis[cur.x][cur.y] = 0;
    q.push(cur);
    while (!q.empty()) {
        cur = q.front();
        q.pop();
        if (cur.x == ea && cur.y == eb && cur.step <= k) {
            flag = 1;
            return;
        }
        for (int i = 0; i < 4; i++) {
            next = cur;                            //先把之前的方向记录到下一个点
            next.x = cur.x + dir[i][0];
            next.y = cur.y + dir[i][1];
            if (next.x < 0 || next.x >= m || next.y < 0 || next.y >= n
                    || map[next.x][next.y] == '*')
                continue;
            if (next.pre == -1)            //如果还未拐过弯
            {
                next.pre = i;               //记录当前的方向
                next.step = 0;                //初始化转弯次数
                if (vis[next.x][next.y] >= next.step){ //如果在这一点的最小转弯次数大于当前走到这一点转弯的次数,那么更新转弯次数,并将符合条件的点入队
                    vis[next.x][next.y] = next.step;
                    q.push(next);
                }
            } else {
                if (cur.pre == i) { //如果该点行进的方向与之前的方向相同,那么只需更新转弯次数就好了,方向在之前已经初始化过了
                    if (vis[next.x][next.y] >= next.step) {
                        vis[next.x][next.y] = next.step;
                        q.push(next);
                    }
                }
                else {          //如果方向不同
                    next.step += 1;
                    next.pre = i;        //如果不同(注意!这里掉头也算转弯!),那么更新转弯次数以及方向
                    if (vis[next.x][next.y] >= next.step) //这里判断一下next.setp是否小于k,这样可以进行优化
                    {
                        vis[next.x][next.y] = next.step;
                        q.push(next);
                    }
                }
            }
        }
    }
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
//  freopen("out.txt", "w", stdout);
#endif
    int t;
    scanf("%d", &t);
    while (t--) {
        flag = 0;
        scanf("%d%d", &m, &n);
        for (int i = 0; i < m; i++)
            scanf("%s", map[i]);
        scanf("%d%d%d%d%d", &k, &sb, &sa, &eb, &ea);    //注意:该题输入时是先输入列在输入行
        sa--;   //我们的输入是从0开始的,而题目中的输入是从1开始的
        sb--;
        ea--;
        eb--;
        bfs();
        if (flag)
            printf("yes\n");
        else
            printf("no\n");
    }
    return 0;
}

1006:原题链接
hdu1175
题意也不难懂。这题和1005还是挺相似的。
我们同样用vis[i][j]来标记到达(i,j)这个点时经过的最小拐弯数。看懂了1005的话1006也不难。

#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<time.h>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<limits.h>
#include<set>
//#define ONLINE_JUDGE
#define eps 1e-8
#define INF 0x7fffffff
#define FOR(i,a) for((i)=0;i<(a);(i)++)
#define MEM(a) (memset((a),0,sizeof(a)))
#define sfs(a) scanf("%s",a)
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define pf(a) printf("%d\n",a)
#define pfI(a) printf("%I64d\n",a)
#define pfs(a) printf("%s\n",a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,num) scanf("%d%d%d",&a,&b,&num)
#define for1(i,a,b) for(int i=(a);i<b;i++)
#define for2(i,a,b) for(int i=(a);i<=b;i++)
#define for3(i,a,b)for(int i=(b);i>=a;i--)
#define MEM1(a) memset(a,0,sizeof(a))
#define MEM2(a) memset(a,-1,sizeof(a))
#define ll __int64
const double PI=acos(-1.0);
template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> inline T Min(T a,T b){return a<b?a:b;}
template<class T> inline T Max(T a,T b){return a>b?a:b;}
using namespace std;
struct Loc {
    int x;
    int y;
    int step;                      //记录行走到某个点时转过的弯
    int dir;                          //记录走到某个点的方式(直走,反向,左转或者右转)
};
int n,m,k;
int mp[1010][1010];
int vis[1010][1010];        //vis[i][j]记录到达某个点最小的拐弯数,
int stx,sty,edx,edy;
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
bool check(int x,int y){
    if(x<0 || x>=n || y<0 || y>=m)
        return false;
    return true;
}
bool bfs(){
    queue<Loc> q;
    for(int i=0;i<=n;i++)
        for(int j=0;j<=m;j++)
            vis[i][j] = INF;        //初始化
    Loc cur,next;
    cur.x = stx;
    cur.y = sty;
    cur.dir = -1;
    cur.step = 0;
    q.push(cur);
    while(!q.empty()){
        cur = q.front();
        q.pop();
        if(cur.x == edx && cur.y == edy && cur.step<=2){ //到达了终点且拐弯数小于等于2
            return true;
        }
        for(int i=0;i<4;i++){
            next.x = cur.x+dir[i][0];
            next.y = cur.y+dir[i][1];
            if(!check(next.x,next.y)) continue; //出界了
            next.step = cur.step;
            next.dir = i;
            if(next.dir != cur.dir && cur.dir != -1)//方向不同且刚开始的方向不为-1(即刚开始未定方向时)
                next.step++;
            if(next.step>2) continue;//如果拐弯数大于2,那么该状态就没用了,舍弃
            if(mp[next.x][next.y] && !(next.x==edx&&next.y==edy)) continue;//next位置上为非零数字且该位置不是终点,舍弃
            if(vis[next.x][next.y]>=next.step){ //符合条件,入队
                vis[next.x][next.y] = next.step;
                q.push(next);
            }
        }
    }
    return false;
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
//  freopen("out.txt", "w", stdout);
#endif
    while(sfd(n,m)!=EOF){
        if(n ==0 && m==0) break;
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                sf(mp[i][j]);
            }
        }
        sf(k);
        for(int i=0;i<k;i++){
            scanf("%d%d%d%d",&stx,&sty,&edx,&edy);
            stx--;sty--;edx--;edy--;
            if(stx == edx && sty == edy){ //如果起点和终点一样,那么指向的是同一块,无法消去
                printf("NO\n");
                continue;
            }
            if(mp[stx][sty] == 0 || mp[edx][edy] == 0){ //某个块是空位置
                printf("NO\n");
                continue;
            }
            if(mp[stx][sty] != mp[edx][edy]){ //要消的两个块不是同个种类的
                printf("NO\n");
                continue;
            }
            if(bfs()) printf("YES\n");
            else
                printf("NO\n");
        }
    }
    return 0;
}

1007:原题链接
题目大意就是给你一个n,让你将1,2,3….n围成一个环,相邻两个数的和要为素数,按字典序输出所有符合排列。
直接用dfs即可,用过的数用vis[i]=1标记,如果这个数在此位置用的不对,那么用vis[i]=0改回来。
此题如果统计一下就知道,在范围里面,除了1以外的奇数,都不可能围成一个素数环。

#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<time.h>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<limits.h>
#include<set>
//#define ONLINE_JUDGE
#define eps 1e-8
#define INF 0x7fffffff
#define FOR(i,a) for((i)=0;i<(a);(i)++)
#define MEM(a) (memset((a),0,sizeof(a)))
#define sfs(a) scanf("%s",a)
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define pf(a) printf("%d\n",a)
#define pfI(a) printf("%I64d\n",a)
#define pfs(a) printf("%s\n",a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,num) scanf("%d%d%d",&a,&b,&num)
#define for1(i,a,b) for(int i=(a);i<b;i++)
#define for2(i,a,b) for(int i=(a);i<=b;i++)
#define for3(i,a,b)for(int i=(b);i>=a;i--)
#define MEM1(a) memset(a,0,sizeof(a))
#define MEM2(a) memset(a,-1,sizeof(a))
#define ll __int64
const double PI=acos(-1.0);
template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> inline T Min(T a,T b){return a<b?a:b;}
template<class T> inline T Max(T a,T b){return a>b?a:b;}
using namespace std;
int n,m,k;
#define M 110
#define N 11010
int f[M];
//vector<int> v[N];
int tmp[25];
int vis[25];
int cnt;
void Init(){              //素数筛选,如果f[i]==0,说明i为素数
    memset(f,0,sizeof f);
    for(int i=2;i<M;i++){
        if(f[i]) continue;
        for(int j=i;i*j<M;j++)
            f[i*j] = 1;
    }
}
void dfs(int cur){
    if(cur == n){
        for(int i=0;i<n;i++)
            printf("%d%c",tmp[i],i+1==n?'\n':' ');
        cnt++;
        return;
    }
    for(int i=2;i<=n;i++){
        if(vis[i]) continue; //每个数字只能使用一次
        if(f[tmp[cur-1]+i]) continue; //如果相邻的数之和不为素数,舍弃
        if(cur == n-1){
            if(f[tmp[cur-1]+i] || f[i+tmp[0]]) continue; //如果是该素数环的最后一个部分,那么得判断它和它之前以及它和该素数环的第一个数之和是否都为素数
        }
        tmp[cur] = i;
        vis[i] = 1; //标记
        dfs(cur+1);
        vis[i] = 0; //恢复标记
    }
    return;
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
//  freopen("out.txt", "w", stdout);
#endif
    Init();
    int kas=1;
    while(sf(n)!=EOF){
        cnt=0;
        memset(vis,0,sizeof vis);
        tmp[0]=1;         //环的第一个为1
        vis[1]=1;
        printf("Case %d:\n",kas++);
        if(n==1 || n%2==0) //不是偶数或者1的话就不用搜了,肯定不能组成素数环
         dfs(1);
//      printf("%d\n",cnt);
        printf("\n");
    }
    return 0;
}

1008:原题链接
hdu1045
题目大意就是给一个n*m地图,里面有两种符号,’.’和’X’,我们所做的就是在’.’处放置blackhouse,条件是同行或者同列不能同时放置超过一个的blackhouse,除非两两之间有’X’符号挡着。问最多可以放置多少blackhouse。
这道题目。。其实我没用搜索,当然,搜索也是可以的。。首先看数据,一共就4*4格子,我暴力枚举,最多也就2^16次的复杂度。所以我用了二进制的枚举,枚举一个二进制串,如果某个位置为1,那么我就在该位置放置blackhouse,如果为0,就不放。放完以后判断下是否符合条件,符合条件的话就更新放置的数目。

#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<time.h>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<limits.h>
#include<set>
//#define ONLINE_JUDGE
#define eps 1e-8
#define INF 0x7fffffff
#define FOR(i,a) for((i)=0;i<(a);(i)++)
#define MEM(a) (memset((a),0,sizeof(a)))
#define sfs(a) scanf("%s",a)
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define pf(a) printf("%d\n",a)
#define pfI(a) printf("%I64d\n",a)
#define pfs(a) printf("%s\n",a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,num) scanf("%d%d%d",&a,&b,&num)
#define for1(i,a,b) for(int i=(a);i<b;i++)
#define for2(i,a,b) for(int i=(a);i<=b;i++)
#define for3(i,a,b)for(int i=(b);i>=a;i--)
#define MEM1(a) memset(a,0,sizeof(a))
#define MEM2(a) memset(a,-1,sizeof(a))
#define ll __int64
const double PI=acos(-1.0);
template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> inline T Min(T a,T b){return a<b?a:b;}
template<class T> inline T Max(T a,T b){return a>b?a:b;}
using namespace std;
int n,m,k;
#define M 110
#define N 11010
int f[M];
char mp[10][10];
char nmap[10][10];
int vis[10][10];
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
int getTheMap(int x){
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            nmap[i][j] = mp[i][j];

    int id=0;     //记录当前是第几个格子
    int xx,yy;
    int res=0;  //记录放置的格子数
    while(x){
        if(x&1){ //x状态下某个格子需要放置blackhosue
            xx = id/n;  //当前格子数/n得到该格子所在的行坐标
            yy = id%n;  //当前格子数%n得到该格子所在的列坐标
            if(nmap[xx][yy] == 'X') return -1; //如果我们当前要放置blackhouse的地方有‘X’,那就放不了,说明该状态无效
            nmap[xx][yy] = 'S'; //我们用‘S’来代表此处有个blackhouse
            res++; //记录放置的格子数
        }
        id++;
        x>>=1;
    }
    return res;
}
bool check(int x,int y){ //判断是否出界或者是否有'X'挡着
    if(x<0 || x>=n || y<0 || y>=n || nmap[x][y] == 'X')
        return false;
    return true;
}
bool ok(int x,int y){

    for(int i=0;i<4;i++){   //从(x,y)处遍历其所在的行和列
        int xx = x+dir[i][0];
        int yy = y+dir[i][1];
        while(check(xx,yy)){
            if(nmap[xx][yy] == 'S') return false; //如果在同一行或者同一列还有blackhouse,那么不符合题目条件,返回false
            xx += dir[i][0];
            yy += dir[i][1];
        }
    }
    return true;
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
//  freopen("out.txt", "w", stdout);
#endif
    while(sf(n)!=EOF && n){
        for(int i=0;i<n;i++)
            sfs(mp[i]);
        int tot = 1<<(n*n); //一共的状态数目
        int ans=0;
        for(int i=1;i<tot;i++){
            int tmp = getTheMap(i); //在i状态下得到新的地图
            if(tmp == -1) continue; //该状态无效
            int flag=1;
            for(int j=0;j<n;j++){
                for(int k=0;k<n;k++){
                    if(nmap[j][k] == 'S'){ //我们从放置blackhouse处遍历它的行和列
                        if(!ok(j,k)){
                            flag=0;
                            break;
                        }
                    }
                }
                if(!flag) break;
            }
            if(flag){ //如果符合条件,那么更新ans(tmp是getTheMap()的返回值,代表放置blackhouse的格子数)
                ans = Max(ans,tmp);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

1009:原题链接
题目大意不难懂。其实我发现这道题目当时虽然过了。但是交到poj上挂了。。然后我就改了改。
其实输出解不难,主要问题是我们怎么避免重复。
比如 3 1 1要等于4,我们先输出3+1,但是后面还有一个1,我们怎么避免再输出一次?这里我们用一个pre记录上一次从这里搜索时的值,如果这次搜索的值还为pre,那么我们就不继续搜索。这样子就能有效地避免重复。

#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<time.h>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<limits.h>
#include<set>
//#define ONLINE_JUDGE
#define eps 1e-8
#define INF 0x7fffffff
#define FOR(i,a) for((i)=0;i<(a);(i)++)
#define MEM(a) (memset((a),0,sizeof(a)))
#define sfs(a) scanf("%s",a)
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define pf(a) printf("%d\n",a)
#define pfI(a) printf("%I64d\n",a)
#define pfs(a) printf("%s\n",a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,num) scanf("%d%d%d",&a,&b,&num)
#define for1(i,a,b) for(int i=(a);i<b;i++)
#define for2(i,a,b) for(int i=(a);i<=b;i++)
#define for3(i,a,b)for(int i=(b);i>=a;i--)
#define MEM1(a) memset(a,0,sizeof(a))
#define MEM2(a) memset(a,-1,sizeof(a))
#define ll __int64
const double PI=acos(-1.0);
template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> inline T Min(T a,T b){return a<b?a:b;}
template<class T> inline T Max(T a,T b){return a>b?a:b;}
using namespace std;
int n,m,k;
#define M 110
#define N 11010
int a[15];
int tmp[15];
int t;
int flag;
void dfs(int cur,int sum,int id){ //cur代表此时存结果数组的下标,sum代表此时的和,id代表我们在某一层搜索到了原数组中的第几个,下次从它开始搜索即可
    if(sum == t){
        for(int i=0;i<cur;i++){
            printf("%d%c",tmp[i],i+1==cur?'\n':'+');
            flag=1;
        }
        return;
    }
    if(sum>t) return; //如果sum>t,那么不符合条件,返回
    int pre=-1;             //pre要在这里定义!
    for(int i=id;i<=n;i++){
        if(a[i] == pre) continue; //如果上一次在这里搜索过的值和这次要搜索的值相同,那么就舍弃
        if(sum+a[i]>t) continue; //如果当前的和+a[i]超过了t,那么舍弃
        pre = a[i];  //pre在此赋值
        tmp[cur] = a[i];
        dfs(cur+1,sum+a[i],i+1); //继续搜索下一层,下标+1,和+a[i],id+1
    }
    return;
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
//  freopen("out.txt", "w", stdout);
#endif
    while(sfd(t,n)!=EOF && n){
        for(int i=1;i<=n;i++)
            sf(a[i]);
        flag=0;
        printf("Sums of %d:\n",t);
        dfs(0,0,1);
        if(!flag)
            printf("NONE\n");
    }
    return 0;
}

1010:原题链接
题目大意就是从‘S’出发到达’D’,问你是否在时间t那一时刻能够到达’D’。注意每个可走的地方都只能走一次,包括’S’和’D’。
首先,我们知道,如果可走的位置总数如果还小于t,那么肯定是无解的,这算是一个特判。
搜索的代码很简单,关键在于剪枝。
有这么两个剪枝条件:
1.假设我们当前所在的位置为(x,y),已经经过了tm时间,那么能到达终点(edx,edy)最短时间为 tm+abs(x-edx)+abs(y-edy),如果这个时间还大于t,那么说明这个状态不可能达到时间t,也就没有必要再搜下去了,舍弃。
2.这个是关键,叫做奇偶剪枝,百度百科的定义在此,简单来说,如果此时坐标为(x,y),那么到达终点(edx,edy)最短步数为abs(x-edx)+abs(y-edy),那么无论你怎么走,最终到达终点所经过的步数的奇偶性,综合最短步数的奇偶性是一样的。不信你可以自己画图看看。所以啊,假设tmp1=abs(x-edx)+abs(y-edy),此时已经过tm时间,那么还剩余tmp2 =t-tm,如果tmp1和tmp2的奇偶性不同,那么无需再搜,该状态无效,怎么都不可能从(x,y)到达(edx,edy)而刚好花费t-tm时间。
做到以上两个剪枝,此题就可以解决。

#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<time.h>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<limits.h>
#include<set>
//#define ONLINE_JUDGE
#define eps 1e-8
#define INF 0x7fffffff
#define FOR(i,a) for((i)=0;i<(a);(i)++)
#define MEM(a) (memset((a),0,sizeof(a)))
#define sfs(a) scanf("%s",a)
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define pf(a) printf("%d\n",a)
#define pfI(a) printf("%I64d\n",a)
#define pfs(a) printf("%s\n",a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,num) scanf("%d%d%d",&a,&b,&num)
#define for1(i,a,b) for(int i=(a);i<b;i++)
#define for2(i,a,b) for(int i=(a);i<=b;i++)
#define for3(i,a,b)for(int i=(b);i>=a;i--)
#define MEM1(a) memset(a,0,sizeof(a))
#define MEM2(a) memset(a,-1,sizeof(a))
#define ll __int64
const double PI=acos(-1.0);
template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> inline T Min(T a,T b){return a<b?a:b;}
template<class T> inline T Max(T a,T b){return a>b?a:b;}
using namespace std;
int n,m,k;
#define M 110
#define N 11010
char mp[10][10];
int vis[10][10];
int t;
int flag;
int edx,edy;
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
bool check(int x,int y){
    if(x<0 || x>=n || y<0 || y>=m || mp[x][y] == 'X')
        return false;
    return true;
}
bool getDis(int x,int y,int tm){
    int ddis = abs(x-edx)+abs(y-edy);
    if(ddis+tm>t) return false; //第一个剪枝
    if(ddis%2 != (t-tm)%2) return false;  //第二个剪枝,奇偶剪枝
    return true;
}
void dfs(int x,int y,int cur){ //x,y代表当前的位置,cur代表经过的时间
    if(x == edx && y == edy && cur == t){
        flag=1;
        return;
    }
    if(!getDis(x,y,cur)) return; //剪枝
    if(flag) return;
//  if(cur>t) return;
    for(int i=0;i<4;i++){         //选择符合条件的点进行搜索
        int xx = x+dir[i][0];
        int yy = y+dir[i][1];
        if(!check(xx,yy)) continue;
        mp[xx][yy] = 'X';
        dfs(xx,yy,cur+1);
        mp[xx][yy] = '.';
    }
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
//  freopen("out.txt", "w", stdout);
#endif
    while(scanf("%d%d%d",&n,&m,&t)!=EOF){
        if(n==0&&m==0&&t==0) break;
        for(int i=0;i<n;i++)
            sfs(mp[i]);
        memset(vis,0,sizeof vis);
        int xx,yy;
        int num=0;
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(mp[i][j] == 'S'){
                    xx = i;
                    yy = j;
                }else if(mp[i][j] == 'D'){
                    edx = i;
                    edy = j;
                }else if(mp[i][j] == '.'){
                    num++;
                }
            }
        }
        if(num+1<t){    //num为'.'数目,+1是因为到达‘D’还可以走一步
            printf("NO\n");
            continue;
        }
        flag=0;
        mp[xx][yy] = 'X'; //走过'S'以后,'S'就不能走了,我们可以直接将其变为'X'
        dfs(xx,yy,0);
        if(flag)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}

以上为此次搜索专题的解题报告,如果有更好的解法可以多交流,谢谢~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值