基础搜索算法题解(I-M)

66 篇文章 0 订阅

练习链接:http://acm.njupt.edu.cn/vjudge/contest/view.action?cid=171#overview



I题 Find The Multiple


Time Limit: 1000MS
Memory Limit: 10000K
Total Submissions: 18823
Accepted: 7618
Special Judge

Description

Given a positive integer n, write a program to find out a nonzero multiple m of n whose decimal representation contains only the digits 0 and 1. You may assume that n is not greater than 200 and there is a corresponding m containing no more than 100 decimal digits.

Input

The input file may contain multiple test cases. Each line contains a value of n (1 <= n <= 200). A line containing a zero terminates the input.

Output

For each value of n in the input print a line containing the corresponding value of m. The decimal representation of m must not contain more than 100 digits. If there are multiple solutions for a given value of n, any one of them is acceptable.

Sample Input

2
6
19
0

Sample Output

10
100100100100100100
111111111111111111

Source

Dhaka 2002

题目链接:http://poj.org/problem?id=1426

题目大意:给一个数n,求其只含有数字0或1的倍数,输出任意可行解

题目分析:DFS,题目说的no more than 100是吓人的,开始以为是大数,其实long long就可以,本题打表也可以;搜索思路:
从1开始判断是否为n的倍数,然后乘10或者乘10加1,找到一个退出即可,因为题目数据范围是1-200,因此搜索深度通过打表决定,深度要求不超过long long范围且对1-200都有解,最后发现18即可。

#include <cstdio>
#define ll long long
ll n, ans;
bool find;

void DFS(ll num, int deep)
{
    if(deep > 18 || find)
        return;
    if(num % n == 0)
    {
        find = true;
        ans = num;
        return;
    }
    DFS(num * 10, deep + 1);
    DFS(num * 10 + 1, deep + 1);
}

int main()
{
    //for(int i = 1; i < 201; i++)
    while(scanf("%lld", &n) != EOF && n)
    {
    //  n = i;
        ans = 0;
        find = false;
        DFS(1, 0);
        printf("%lld\n", ans);
    }
}





J题 Prime Path

Time Limit: 1000MS
Memory Limit: 65536K
Total Submissions: 11991
Accepted: 6809

Description

The ministers of the cabinet were quite upset by the message from the Chief of Security stating that they would all have to change the four-digit room numbers on their offices.
— It is a matter of security to change such things every now and then, to keep the enemy in the dark.
— But look, I have chosen my number 1033 for good reasons. I am the Prime minister, you know!
— I know, so therefore your new number 8179 is also a prime. You will just have to paste four new digits over the four old ones on your office door.
— No, it’s not that simple. Suppose that I change the first digit to an 8, then the number will read 8033 which is not a prime!
— I see, being the prime minister you cannot stand having a non-prime number on your door even for a few seconds.
— Correct! So I must invent a scheme for going from 1033 to 8179 by a path of prime numbers where only one digit is changed from one prime to the next prime.

Now, the minister of finance, who had been eavesdropping, intervened.
— No unnecessary expenditure, please! I happen to know that the price of a digit is one pound.
— Hmm, in that case I need a computer program to minimize the cost. You don't know some very cheap software gurus, do you?
— In fact, I do. You see, there is this programming contest going on... Help the prime minister to find the cheapest prime path between any two given four-digit primes! The first digit must be nonzero, of course. Here is a solution in the case above.
1033
1733
3733
3739
3779
8779
8179
The cost of this solution is 6 pounds. Note that the digit 1 which got pasted over in step 2 can not be reused in the last step – a new 1 must be purchased.

Input

One line with a positive number: the number of test cases (at most 100). Then for each test case, one line with two numbers separated by a blank. Both numbers are four-digit primes (without leading zeros).

Output

One line for each case, either with a number stating the minimal cost or containing the word Impossible.

Sample Input

3
1033 8179
1373 8017
1033 1033

Sample Output

6
7
0

Source


题目链接:http://poj.org/problem?id=3126

题目大意:输入两个四位素数,求从第一个变换到第二的最小变换步数,每次只能更改四位里一位的值并且要求更改后的数字仍然是素数。

题目分析:BFS,像这类求最短的搜索通常都是BFS,从第一个数字开始,每位拆分,凡是符合条件的素数进队列,这里判素数需要一个素数筛,
我们不需要考虑怎样得到最短的步数,因为采用广度优先搜索出来的解必定最短。拆数字的时候记得还原,举个例子,比如1033是个素数,拆十位
的时候10x3 (0 <= x <= 9)这时候若找不到可以进队列的值,要将其还原成1033,本题有一点很重要,我做的时候忽略掉了,就是怎么变换数字都
要求是4位的,因此在拆千位的时候是从1-9而不是0-9!
这题代码写的相当丑。。。

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
int st, ed;
int prime[1000001];
bool used[1000001];

struct NUM
{
    int num;
    int step;
};

void get_prime()  //素数筛
{ 
    memset(prime, 1, sizeof(prime));  
    prime[1] = 0;  
    for(int i = 2; i <= 1000; i++)    
        if(prime[i])    
            for(int j = i * i; j <= 1000000; j += i)    
                prime[j] = 0;  
}

int BFS()
{
    memset(used, false, sizeof(used));
    queue<NUM> q;
    NUM s, tmp, cur;
    s.num = st;
    s.step = 0;
    used[st] = true;
    q.push(s);
    while(!q.empty())
    {
        cur = q.front();
        q.pop();
        if(cur.num == ed)
            return cur.step;
        tmp = cur;
        tmp.num -= (tmp.num % 10);
        for(int i = 0; i < 10; i++) //拆个位
        {
            tmp.num += i;
            tmp.step++;
            if(tmp.num == ed)
                return tmp.step;
            //若该数字没使用过且是个素数则标记为已使用并进队列
            if(!used[tmp.num] && prime[tmp.num])
            {
                used[tmp.num] = true;
                q.push(tmp);
            }
            tmp.num -= i;   //还原
            tmp.step--;
        }
        tmp = cur;
        tmp.num -= (((tmp.num / 10) % 10) * 10);
        for(int i = 0; i < 10; i++) 拆十位
        {
            tmp.num += (i * 10);
            tmp.step++;
            if(tmp.num == ed)
                return tmp.step;
            if(!used[tmp.num] && prime[tmp.num])
            {
                used[tmp.num] = true;
                q.push(tmp);
            }
            tmp.num -= (i * 10);
            tmp.step--;
        }
        tmp = cur;
        tmp.num -= (((tmp.num / 100) % 10) * 100);
        for(int i = 0; i < 10; i++) //拆百位
        {
            tmp.num += (i * 100);
            tmp.step++;
            if(tmp.num == ed)
                return tmp.step;
            if(!used[tmp.num] && prime[tmp.num])
            {
                used[tmp.num] = true;
                q.push(tmp);
            }
            tmp.num -= (i * 100);
            tmp.step--;
        }
        tmp = cur;
        tmp.num -= ((tmp.num / 1000) * 1000);
        for(int i = 1; i < 10; i++) //拆千位
        //!!!千位的第一位不能是0!
        {
            tmp.num += (i * 1000);
            tmp.step++;
            if(tmp.num == ed)
                return tmp.step;
            if(!used[tmp.num] && prime[tmp.num])
            {
                used[tmp.num] = true;
                q.push(tmp);
            }
            tmp.num -= (i * 1000);
            tmp.step--;
        }
    }
    return -1;
}

int main()
{
    int n, ans;
    scanf("%d", &n);
    get_prime();
    while(n --)
    {
        scanf("%d %d", &st, &ed);
        ans = BFS();
        if(ans == -1)
            printf("Impossible\n");
        else
            printf("%d\n", ans);
    }
}







k题 Pots

Time Limit: 1000MS
Memory Limit: 65536K
Total Submissions: 10300
Accepted: 4362
Special Judge

Description

You are given two pots, having the volume of A and B liters respectively. The following operations can be performed:

  1. FILL(i)        fill the pot i (1 ≤i≤ 2) from the tap;
  2. DROP(i)      empty the pot i to the drain;
  3. POUR(i,j)    pour from pot i to potj; after this operation either the potj is full (and there may be some water left in the poti), or the poti is empty (and all its contents have been moved to the potj).

Write a program to find the shortest possible sequence of these operations that will yield exactlyC liters of water in one of the pots.

Input

On the first and only line are the numbers A, B, and C. These are all integers in the range from 1 to 100 andC≤max(A,B).

Output

The first line of the output must contain the length of the sequence of operationsK. The followingK lines must each describe one operation. If there are several sequences of minimal length, output any one of them. If the desired result can’t be achieved, the first and only line of the file must contain the word ‘impossible’.

Sample Input

3 5 4

Sample Output

6
FILL(2)
POUR(2,1)
DROP(1)
POUR(2,1)
FILL(2)
POUR(2,1)

Source

Northeastern Europe 2002, Western Subregion

题目链接:http://poj.org/problem?id=3414

题目大意:两个杯子容积为A和B,三类操作,装满,倒光,一个杯子倒到另一个杯子里(倒的时候是尽可能将另一个杯子倒满,倒水的杯子可以有剩余),求最小的操作次数能使其中一个杯子中水的体积为C

题目分析:求最小操作次数并输出,BFS,三类操作,六种情况,分别讨论,vis[a][b]记录某第一个杯子a体积水和第二个杯子b体积水的情况有没有出现过,本题主要难在输出,开始用一维pre数组标记,发现行不通,因为设pre[a] = b是b在a之后操作,则若出现循环操作例如pre[2]=1,pre[1] = 2则程序会死循环,因此改用二维数组标记pre[step][a] = b,表示在第step步时b是a之后的操作,最后逆序输出即可
代码依旧奇丑无比


#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
int A, B, C, ans;
int re[100000], cnt = 0;
bool vis[105][105];
char out[7][10] = {"","FILL(1)", "FILL(2)", "DROP(1)", "DROP(2)", "POUR(1,2)", "POUR(2,1)"};

struct NUM
{
    int a, b; //a, b表示两个杯子中水的体积
    int step; //step表示操作次数
    int now;  //now表示当前的操作序号
    int pre[5000][10]; //pre记录顺序
};

void BFS()
{
    memset(vis, false, sizeof(vis));
    queue<NUM> q;
    NUM st, t, cur;
    memset(st.pre, 0, sizeof(st.pre));
    st.a = 0;
    st.b = 0;
    st.step = 0;
    st.now = 0;
    q.push(st);
    while(!q.empty())
    {
        t = q.front();
        cur = t;
        q.pop();
        if(t.a == C || t.b == C)
        {
            printf("%d\n", t.step);
            while(t.now) //迭代得到操作序列
            {
                re[cnt++] = t.now;
                t.now = t.pre[t.step--][t.now];
            }
            return;
        }
        for(int i = 1; i <= 6; i++)
        {
            t = cur;  //每次要将t还原!
            if(i == 1)//fill(1)
            {
                t.now = 1;
                t.a = A;
                t.step ++;
                if(!vis[t.a][t.b])
                {
                    vis[t.a][t.b] = true;
                    t.pre[t.step][t.now] = cur.now;
                    q.push(t);
                }
            }
            if(i == 2) //fill(2)
            {
                t.now = 2;
                t.b = B;
                t.step ++;
                if(!vis[t.a][t.b])
                {
                    vis[t.a][t.b] = true;
                    t.pre[t.step][t.now] = cur.now;
                    q.push(t);
                }
            }
            if(i == 3) // drop(1)
            {
                t.now = 3;
                t.a = 0;
                t.step ++;
                if(!vis[t.a][t.b])
                {
                    vis[t.a][t.b] = true;
                    t.pre[t.step][t.now] = cur.now;
                    q.push(t);
                }
            }
            if(i == 4)//drop(2)
            {
                t.now = 4;
                t.b = 0;
                t.step ++;
                if(!vis[t.a][t.b])
                {
                    vis[t.a][t.b] = true;
                    t.pre[t.step][t.now] = cur.now;
                    q.push(t);
                }
            }
            if(i == 5)//pour(1,2)
            {
                t.now = 5;
                int tmp = t.b;
                if(t.b + t.a >= B) 
                {
                    t.b = B;
                    t.a -= (B - tmp);
                }
                else
                {
                    t.b += t.a;
                    t.a = 0;
                }
                t.step ++;
                if(!vis[t.a][t.b])
                {
                    vis[t.a][t.b] = true;
                    t.pre[t.step][t.now] = cur.now;
                    q.push(t);
                }
            }
            if(i == 6) //pour(2,1)
            {
                t.now = 6;
                int tmp = t.a;
                if(t.b + t.a >= A)
                {
                    t.a = A;
                    t.b -= (A - tmp);
                }
                else
                {
                    t.a += t.b;
                    t.b = 0;
                }
                t.step ++;
                if(!vis[t.a][t.b])
                {
                    vis[t.a][t.b] = true;
                    t.pre[t.step][t.now] = cur.now;
                    q.push(t);
                }
            }
        }
    }    
    ans = -1;
    return;
}

int main()
{
    scanf("%d %d %d", &A, &B, &C);
    BFS();
    if(ans == -1)
        printf("impossible\n");
    else
        for(int i = cnt - 1; i >= 0; i--)
            printf("%s\n", out[re[i]]);
}






L题 Dungeon Master


Time Limit: 1000MS
Memory Limit: 65536K
Total Submissions: 17406
Accepted: 6769

Description

You are trapped in a 3D dungeon and need to find the quickest way out! The dungeon is composed of unit cubes which may or may not be filled with rock. It takes one minute to move one unit north, south, east, west, up or down. You cannot move diagonally and the maze is surrounded by solid rock on all sides.

Is an escape possible? If yes, how long will it take?

Input

The input consists of a number of dungeons. Each dungeon description starts with a line containing three integers L, R and C (all limited to 30 in size).
L is the number of levels making up the dungeon.
R and C are the number of rows and columns making up the plan of each level.
Then there will follow L blocks of R lines each containing C characters. Each character describes one cell of the dungeon. A cell full of rock is indicated by a '#' and empty cells are represented by a '.'. Your starting position is indicated by 'S' and the exit by the letter 'E'. There's a single blank line after each level. Input is terminated by three zeroes for L, R and C.

Output

Each maze generates one line of output. If it is possible to reach the exit, print a line of the form
Escaped in x minute(s).

where x is replaced by the shortest time it takes to escape.
If it is not possible to escape, print the line
Trapped!

Sample Input

3 4 5
S....
.###.
.##..
###.#

#####
#####
##.##
##...

#####
#####
#.###
####E

1 3 3
S##
#E#
###

0 0 0

Sample Output

Escaped in 11 minute(s).
Trapped!

Source

Ulm Local 1997

题目链接:http://poj.org/problem?id=2251

题目大意:三维迷宫,给起点和终点,求走通的最小步数

题目分析:裸BFS,没啥可说的,和二维的差不多,本博客BFS栏中有二维迷宫,理解了二维迷宫,三维的一样做

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
int const MAX = 35;
int d[MAX][MAX][MAX];
int vis[MAX][MAX][MAX];
int l, r, c;
int sx, sy, sz, ex, ey, ez;
int dx[] = {0,0,0,0,1,-1};  
int dy[] = {0,0,1,-1,0,0};  
int dz[] = {1,-1,0,0,0,0}; 
struct Node
{
    int x, y, z;
    int step;
};

int BFS()
{
    memset(vis, 0, sizeof(vis));
    queue <Node> q;
    Node st, t;
    st.x = sx;
    st.y = sy;
    st.z = sz;
    vis[sx][sy][sz] = 1;
    st.step = 0;
    q.push(st);
    while(!q.empty())
    {
        st = q.front();
        q.pop();
        for(int i = 0; i < 6; i++)
        {
            t = st;
            t.x += dx[i];
            t.y += dy[i];
            t.z += dz[i];
            t.step++;
            if(t.x == ex && t.y == ey && t.z == ez)
                return t.step;
            if(t.x >= l || t.y >= r || t.z >= c || t.x < 0 || t.y < 0 || t.z < 0)
                continue;
            if(d[t.x][t.y][t.z] == 0 || vis[t.x][t.y][t.z])
                continue;
            vis[t.x][t.y][t.z] = 1;
            q.push(t);
        }
    }
    return -1;
}

int main()
{
    char s[35];
    int ans;
    while(scanf("%d %d %d", &l, &r, &c) != EOF && (l + r + c))
    {
        memset(d, 1, sizeof(d));
        ans = -1;
        for(int i = 0; i < l; i++)
        {
            for(int j = 0; j < r; j++)
            {
                scanf("%s", s);
                for(int k = 0; k < c; k++)
                {
                    if(s[k] == '#')
                        d[i][j][k] = 0;
                    if(s[k] == 'S')
                    {
                        sx = i; 
                        sy = j;
                        sz = k;
                    }
                    if(s[k] == 'E')
                    {
                        ex = i;
                        ey = j;
                        ez = k;
                    }
                }
            }
        }
        ans = BFS();
        if(ans == -1)
            printf("Trapped!\n");
        else
            printf("Escaped in %d minute(s).\n", ans);
    }
}







M题 STAMPS

Time Limit: 1000MS
Memory Limit: 10000K
Total Submissions: 16353
Accepted: 4635

Description

Have you done any Philately lately?

You have been hired by the Ruritanian Postal Service (RPS) to design their new postage software. The software allocates stamps to customers based on customer needs and the denominations that are currently in stock.

Ruritania is filled with people who correspond with stamp collectors. As a service to these people, the RPS asks that all stamp allocations have the maximum number of different types of stamps in it. In fact, the RPS has been known to issue several stamps of the same denomination in order to please customers (these count as different types, even though they are the same denomination). The maximum number of different types of stamps issued at any time is twenty-five.

To save money, the RPS would like to issue as few duplicate stamps as possible (given the constraint that they want to issue as many different types). Further, the RPS won't sell more than four stamps at a time.

Input

The input for your program will be pairs of positive integer sequences, consisting of two lines, alternating until end-of-file. The first sequence are the available values of stamps, while the second sequence is a series of customer requests. For example:

1 2 3 0 ; three different stamp types
7 4 0 ; two customers
1 1 0 ; a new set of stamps (two of the same type)
6 2 3 0 ; three customers

Note: the comments in this example are *not* part of the data file; data files contain only integers.

Output

For each customer, you should print the "best" combination that is exactly equal to the customer's needs, with a maximum of four stamps. If no such combination exists, print "none".
The "best" combination is defined as the maximum number of different stamp types. In case of a tie, the combination with the fewest total stamps is best. If still tied, the set with the highest single-value stamp is best. If there is still a tie, print "tie".

For the sample input file, the output should be:

7 (3): 1 1 2 3
4 (2): 1 3
6 ---- none
2 (2): 1 1
3 (2): tie

That is, you should print the customer request, the number of types sold and the actual stamps. In case of no legal allocation, the line should look like it does in the example, with four hyphens after a space. In the case of a tie, still print the number of types but do not print the allocation (again, as in the example).Don't print extra blank at the end of each line.

Sample Input

1 2 3 0	; three different stamp types
7 4 0		; two customers
1 1 0		; a new set of stamps (two of the same type)
6 2 3 0	; three customers

Sample Output

7 (3): 1 1 2 3 
4 (2): 1 3 
6 ---- none
2 (2): 1 1
3 (2): tie

Source



题目链接:http://poj.org/problem?id=1010

题目大意:有多种类型的邮票,每种类型有特定的面值(不同类型面值可以相同),给出每个客户所需的面值总和,客户的需求为:使购买邮票的总面值为所
求面值总和。若不存在满足需求的方案,输出none;否则,输出最佳方案。
  最佳方案的定义如下:
  1.种类最多
  2.张数最少
  3.单张面值最大
  经上述约束仍不止一个最佳方案,输出tie
  其中,每位顾客购买邮票张数不超过4

题目分析:题意限制条件很多啊,dfs的时候根据条件更新就可以了,详细见代码


#include <cstdio>
#include <algorithm>
using namespace std;

//不同种类的面值,先前最佳解,当前解
int kind[100], pre[4], cur[4];
//种类,需求,先前已存在最佳解的种类数、张数、单张最大面值
int type, need, pKind, pNum, pVal;
//最佳方案数
int ans;

//当前可以购买的种类,上次购买的种类,当前购买的种类数、张数、单张最大面值
void DFS(int k, int lKind, int cKind, int cNum, int cVal, int cost)
{
    if(cNum > 4 || (cNum == 4 && cost != need)) 
        return;
    if(cost == need) //可行方案
    {
        if( (pKind == 0) || //先前没有可行解
            (cKind > pKind) ||  //种类多
            (cKind == pKind && cNum < pNum) || //张数少
            (cKind == pKind && cNum == pNum && cVal > cVal)) //面值大
        {
            pKind = cKind;
            pNum = cNum;
            pVal = cVal;
            for(int i = 0; i < cNum; i++)
                pre[i] = cur[i];
            ans = 1;
        }
        else if(cKind == pKind && cNum == pNum && cVal == pVal) //存在多种最佳方案
            ans ++;
        return;
    }
    for(int i = k; i < type; i++)
    {
        if(cost + kind[i] > need) //排过序
            break;
        int tKind = cKind, tVal = cVal;
        if(lKind != i) 
            tKind = cKind + 1;
        if(cVal < kind[i]) 
            tVal = kind[i];
        cur[cNum] = kind[i];
        DFS(i, i, tKind, cNum + 1, tVal, cost + kind[i]);
    }
}

int main()
{
    while(scanf("%d", &kind[0]) != EOF)
    {
        type = 0;
        while(kind[type] != 0)
            scanf("%d", &kind[++type]);
        sort(kind, kind + type);
        while(scanf("%d", &need) && need)
        {
            pKind = pNum = pVal = 0;
            ans = 1;
            DFS(0, -1, 0, 0, 0, 0);
            if(pKind == 0)
                printf("%d ---- none\n", need);
            else if(ans > 1)
                printf("%d (%d): tie\n", need, pKind);
            else
            {
                printf("%d (%d): ", need, pKind);
                for(int i = 0; i < pNum - 1; i++)
                    printf("%d ", pre[i]);
                printf("%d\n", pre[pNum - 1]);
            }
        }
    }
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值