您的位置:首页 > 其它

搜索题【入门】

2015-12-04 15:24 232 查看

搜索题【入门】

HZNU-1507-K进制数

题目链接:HZNU-1507

题目大意:给出K进制数的位数,问存在多少种情况,不含两个连续的0,且不以0开头

题目思路:DFS

[code]#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <string>
#include <cstring>
using namespace std;
int ans = 0;
int n,k;
void dfs(int x,int y)
{
    if (y == 0)
    {
        ans++;
        return;
    }
    if (x != 0) dfs(0,y-1);
    for (int i = 1; i < k; i++)
    {
        dfs(i,y-1);
    }
}
int main(){
    cin >> n >> k;
    for (int i = 1; i < k; i++)
        dfs(i,n-1); 
    cout << ans << endl;
    return 0;
}


HDU-2553-N皇后问题

题目链接:HDU-2553

题目大意:在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。你的任务是,对于给定的N,求出有多少种合法的放置方法。

题目思路:采用回溯。一行一行的放皇后, 然后再递归判断是否与之前已放好的皇后有冲突,一旦有冲突,则不需要继续下一行的搜索,直接返回(省去不必要的枚举)。

以下是代码:

[code]#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <string>
#include <cstring>
using namespace std;
int line[15];
int n;
int tot = 0;
int ans[15];
void dfs(int row)//第row行
{
    if (row == n)   //
    {
        tot++;
        return;
    }
    for (int i = 0; i < n; i++)
    {
        line[row] = i;  //假设第row行皇后放在i这列
        int ok = 1;
        for (int j = 0; j < row; j++)
        {   
            //判断前面row-1行,i列是否放了皇后,以及对角线是否有冲突
            if (line[j] == i || line[row] - row == line[j] - j || line[row] + row == line[j] + j)
            {
                ok = 0;
                break;
            }
        }
        if (ok)
        {
            dfs(row + 1);
        } 
    }
}
int main(){
    for (n = 1; n <= 10; n++)  //预处理,防止超时
    {
        tot = 0;
        dfs(0);
        ans
 = tot;
    }
    while(cin >> n && n)
    {
        cout << ans
 << endl;
    } 
    return 0;
}


HDU-1016–Prime Ring Problem(素数环)

题目链接:HDU-1016

题目大意:输入正整数n,把整数1,2,3,…,n组成一个环,使得相邻两个整数之和为素数。输出时从整数1开始。

题目思路:DFS,注意判断最后一个和第一个数相加也是素数

以下是代码:

[code]#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <string>
#include <cstring>
using namespace std;
int prm[100000];
const int MAXV = 1e5; 
bool isPrime[MAXV+1]; 
int size=0; 
int A[30];
int vis[30];
//获得素数
void getPrime()  
{  
    memset(isPrime, true, sizeof(isPrime));
    int sq = sqrt((double)MAXV) + 1; 
    int i,j,k;  
    for(i = 2;i <= sq; i++)  
        if(isPrime[i])  
    for(j = 2,k = MAXV/i+1;j < k;j++)  
        isPrime[i*j] = false;  
    for( i = 2 ; i <= MAXV; i++)  
        if(isPrime[i])    
            prm[size++] = i;
    isPrime[0] = isPrime[1] = false;
}  
int n;
int cnt = 1;
int first = 1;
void dfs(int cur)
{
    if (cur == n + 1 && isPrime[A
 + A[1]])
    {
        printf("%d",A[1]); 
        for(int i = 2; i <= n; i++)
        {
            printf(" %d",A[i]);
        } 
        printf("\n");
        return;
    }
    for (int i = 1; i <= n; i++)
    {
        if (!vis[i] && isPrime[i + A[cur - 1]])
        {
            vis[i] = 1;
            A[cur] = i;
            dfs(cur + 1);
            vis[i] = 0;
        }
    }
}

int main(){
    getPrime();
    while(scanf("%d",&n) != EOF)
    {
        printf("Case %d:\n",cnt++); 
        memset(vis,0,sizeof(vis));
        memset(A,0,sizeof(A));
        vis[1] = 1;
        A[1] = 1;
        if (n % 2 != 1) dfs(2); 
        printf("\n");
    }
    return 0;
}


HDU-1241-Oil Deposits

题目链接:HDU-1241

题目思路:在一个矩阵里,有些格子是‘@’,有些不是,相邻(上、下、左、右、左上、右上、左下、右下)的格子如果也是‘@’,那么他们属于同一个矿井,问总共有多少个矿井。

题目思路:DFS,求连通块个数。

以下是代码:

[code]#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <string>
#include <cstring>
using namespace std;
string s[101];
int vis[105][105];
int flag = 0;
int m,n;
void dfs(int c,int r)
{
    if (c >= m || c < 0 || r >= n || r < 0) return;
    if (vis[c][r] || s[c][r] != '@') return;
    vis[c][r] = 1;
    if (s[c][r] == '@') flag = 1;
    for (int i = -1; i <= 1; i++)
    {
        for (int j = -1; j <= 1; j++)
        {
            if (i == 0 && j == 0) continue;
            dfs(c + i,r + j);
        }
    }
}
int main(){

    while(cin >> m >> n)
    {
        if (m == 0 && n == 0) break;
        for (int i = 0; i < m; i++)
        {
            cin >> s[i];
        }
        int ans = 0;
        memset(vis,0,sizeof(vis));
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (s[i][j] == '@')
                {
                    dfs(i,j);
                    if (flag) ans++;
                    flag = 0;
                } 

            }
        }
        cout << ans << endl;
    } 
    return 0;
}


HDU-1312-Red and Black

题目链接:HDU-1312

题目大意:‘@’代表人其实位置,‘.’代表可走格子,‘#’代表‘墙’。问这个人最多能走几个格子。可以走的方向有(上、下、左、右)四个方向。

题目思路:DFS,从‘@’开始搜,如果是可走位置继续搜,如果碰到墙则停止该条路的搜索。

以下是代码:

[code]#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <string>
#include <cstring>
using namespace std;
string s[25];
int vis[25][25];
int w,h;
int ans = 0;
void dfs(int c,int r)
{
    if (c >= h || c < 0 || r >= w || r < 0) return;
    if (vis[c][r] || s[c][r] == '#') return;
    vis[c][r] = 1;
    ans++;
    dfs(c + 1,r);
    dfs(c - 1,r);
    dfs(c,r + 1);
    dfs(c,r - 1);
}
int main(){
    while(cin >> w >> h)
    {
        if (w == 0 && h == 0) break;
        int poi = -1,poj = -1;
        ans = 0;
        memset(vis,0,sizeof(vis));
        for (int i = 0; i < h; i++)
        {
            for (int j = 0; j < w; j++)
            {
                cin >> s[i][j];
                if (s[i][j] == '@') poi = i,poj = j;
            }
        }
        dfs(poi,poj);
        cout << ans << endl;
    }
    return 0;
}


HDU-1584-蜘蛛牌

题目链接:HDU-1584

题目大意:小的牌移动到大的牌上面。给出每个牌的位置,问叠成一堆牌的最小移动距离

题目思路:DFS+剪枝

以下是代码:

[code]#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <string>
#include <cstring>
using namespace std;
int p[20];
int vis[20];
int ans = 9999999;
void dfs(int cur,int sum)  //cur表示解决了几张牌,sum表示目前移动的距离
{
    if (sum >= ans) return;  //剪枝
    if (cur == 9)  //10是保持不动
    {
        ans = sum;
        return; //回溯
    }
    for (int i = 1; i < 10; i++)
    {
        if (!vis[i])  //这张牌没有被处理过
        {
            vis[i] = 1;
            for (int j = i + 1; j <= 10; j++)
            {
                if (!vis[j])
                {
                    dfs(cur + 1,sum + abs(p[i] - p[j]));  //小的牌叠到大的牌上面
                    break; //注意不要再这个地方回溯 如果回溯了 就像是又一个全排列 而且牌得移动不合理,比如2移到6了,结果回溯就直接跳过3~6到了7的下面
                }
            }
            vis[i] = 0;   //这里回溯
        }       
    }
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(vis,0,sizeof(vis));
        ans = 9999999;
        for (int i = 1; i <= 10; i++)
        {
            int num;
            scanf("%d",&num);
            p[num] = i; //牌面为num在第i个位置 
        }
        dfs(0,0);
        printf("%d\n",ans);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: