您的位置:首页 > 其它

hdu 4474 Yet Another Multiple Problem 模型转换 BFS搜索

2013-04-25 19:48 387 查看


hdu
4474 Yet Another Multiple Problem 模型转换 BFS搜索

题意:
  给一个N(n<=1e4), M个数字(长度为1),问最小的数x(x%n=0) 不包含这m个数。
思路:
  直接求,没想出解法.
  对于一个数 x%n = m, 则 x` = x*10+i , 有 m` = (m*10+i)%n , 例如:m=123%5=3,当在123后加一位数时, 比如 1231 ,则 1231%5=1 , 可以用 m得来。 m' = (m*10+i)%n,
即 m'=(3*10+1)%5=1;因此,当已
搜索到x这个数时,如123,再加一位数继续搜索,如1231,直接用x(123)这个数的m,就可以算出m' .
  我们可以利用 除了M个数字外的 数来构造这个 X.


c:末尾的那个数字 (保存新加入的一个数)

m:这个节点所代表的数字对n取模的值

f:父节点

对于一个节点,如果在其后面加一个数字i,那么新的m值=(m*10 + i)%n
  因为需要最小的, 则其长度与字典序排列皆最小. 通过BFS进行搜索. 每一个 模n的余数之取第一次出现的,
因为之后再出现的. 只可能更长或者更大. 必定不是最优解.这里用vis
标记m是否出现了,
  搜索节点,保存三个信息: 当前x的最后一位, 当前x%n的余数, 当前节点的父亲节点.
  结果输出利用记忆父亲节点 ,然后递归输出即可.

#include<cstdio>
#include<cstring>
#include<cstdlib>

const int N = (int)1e4+10;

struct node{        //节点保存3个信息。
    int m, f;
    char c;
}Q
, tmp;

bool vis
,legal[10];
int n, m;

void print(int k){              //当加入一个数得到的m=0,即为n的倍数。则回溯把c逐个输出
    //if( k == -1 ) return;
    if( Q[k].f != -1 ) print(Q[k].f);   //f记录的是父节点,也就是数组下标。次节点是由父节点推过来的    
    printf("%c", Q[k].c );              //通过回溯,找出路径,也就是逐个输出答案。
}
int main(){
    int Case = 1;    
    while( scanf("%d%d",&n,&m) != EOF){
        memset( vis, 0, sizeof(vis));    
        memset( legal, 0, sizeof(legal));
        for(int x, i = 0; i < m; i++){     //输入m个数
            scanf("%d",&x);
            legal[x] = 1;    
        }    
        int l = 0, r = 0, res = -1;     //l队头指针,r队尾指针,res :搜到符合结果的数的位置
        for(int i = 1; i < 10; i++){     //因为第一位不能为0,所以先把第一位入队
            if( !legal[i] ){            //入队的数不能使m个数里面的。
                tmp.c = i+'0'; tmp.m = i%n; tmp.f = -1;  //3个信息
            //    if( !vis[tmp.m] ){
                    vis[tmp.m] = 1;       //算出m,标记起来。表示已经出现过。
                    Q[r++] = tmp;         //入队,队尾指针后移
                    if( tmp.m == 0 ){     //如果m=0;则是答案,res指向答案这个元素
                        res = r-1; break;     // 因为上面,r++,所以减回头
                    }    
        //        }
            }    
        } 
        while( (l < r) && (res==-1) ){       //搜索,当l=r ,空队
            for(int i = 0; i < 10; i++){       //加上一位数,从0~9之间枚举,不包括哪些非法数字
                tmp.m = (Q[l].m*10+i)%n; tmp.c = i+'0'; tmp.f = l;  //算出3个信息。  
                if( !legal[i] && !vis[tmp.m] ){      //若加上的数合法,并且算出的第一次出现
                    vis[tmp.m] = 1;                //标记
                    Q[r++] = tmp;                //入队
                    if( tmp.m == 0 ){          //若算出的m=0;就是答案
                        res = r-1; break;    
                    }    
                }
            }
            l++;          //队头指针后移,接着搜索。
        }    
        printf("Case %d: ", Case++);      
        if( res == -1 ) printf("-1\n");
        else    {print(res);puts("");}     //此时res指向队列里答案的位置,也就是数组下标
    }    
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: