HDU 4474 Yet Another Multiple Problem BFS

题意:求m的倍数中不包含一些数码的最小倍数数码是多少。比如15 ,不包含0  1 3,答案是45.

      BFS过程:用b[]记录可用的数码。设一棵树,树根为-1.树根的孩子是所有可用的数码,孩子的孩子也是所有可用的数码。这样从根到叶子节点这条路径所组成的数表示一个可行的数。

                                                     __                 __

      剪枝:(A % m ==  B % m)  =>  (AX % m ==  BX % m)   即如果搜索到一个数X, X%m == a (a !=0) , 则以后如果搜索到Y , Y%m == a,则不必继续搜索。 这样一棵树是有尽头的。

     所有这棵树的节点最多才m-1个。

      这个剪枝在逻辑电路课上突然灵光突现,昨天模拟赛就怎么也想不来了,额,熬夜要变傻子了。 还有碰到两个陷阱,m==0的时候要特判。不能用节点来直接保存答案,long long 不够用,递归输出答案吧。

#include <stdio.h>
#include <string.h>
//#include <queue>
using namespace std;
#define MAXN 100005
int N,m;
bool vis[MAXN];
int pre[MAXN];
int a[102];
int b[102];
int num[MAXN];
int que[MAXN];
int front,rear;
void print(int x) //递归从前往后输出答案 
{
    if (pre[x] != -1 )
        print(pre[x]);
    printf("%d",num[x]);
    return;
}
int main()
{
    int i,j,k,x,cas=0;
    int casb,ans;
    while (scanf("%d%d",&N,&m)!=EOF)
    {
        printf("Case %d: ",++cas);
        int x;
        int casb=0;
        memset(a, 0, sizeof(a));
        memset(b, 0, sizeof(b));
        memset(vis,0 , sizeof(vis));
        for (i=0; i<m; i++)
        {
            scanf("%d",&x);
            a[x]=1;
        }
        for (i = 0; i <= 9; i++)
            if (a[i] == 0)
                b[casb++]=i;
        if (N == 0)  //特判
        {
            if (b[0] == 0)
                printf("0\n");
            else
                printf("-1\n");
            continue;
        }

        int flag=1;
        int ans;
        front=0;rear=0;
        for (i = 0; i < casb; i++)  //最高位
            if (b[i]!=0)
            {
                que[rear++]=b[i]%N;
                vis[b[i]%N]=true;
                num[rear-1]=b[i];
                pre[rear-1]=-1;
                if (b[i] % N == 0)
                {
                    ans=b[i];
                    flag=0;
                    break;
                }
            }
        if (flag == 0)
        {
            printf("%d\n",ans);
            continue;
        }
        int tmp;
        ans=-1;
        flag=0;
        while (front != rear) //bfs
        {
            tmp=que[front];

            for (i = 0; i < casb; i++)
                if (!vis[(tmp*10+b[i]) % N])  //剪枝
                {
                    que[rear]=(tmp*10+b[i])% N;
                    vis[(tmp*10+b[i])% N ]=true;
                    pre[rear] = front;//保存父节点
                    num[rear] = b[i]; //保存本节点这个位数的数字
                    if ((tmp*10+b[i]) % N == 0)
                    {
                        print(rear);
                        printf("\n");
                        flag=1;
                        break;
                    }
                    rear++;
                }
            if (flag)
                break;
            front++;
        }
        if (flag == 0)
            printf("-1\n");

    }
    return 0;
}

 

posted on 2013-09-27 17:13  six_god  阅读(128)  评论(0编辑  收藏  举报

导航