URAL 1495. One-two, One-two 2 DP or BFS?
这个题就是给一个数n,看用1,2组成数能否找出一个最小的数使得能被n整除,如果能输出这个数,并且要求这个数长度不能超过30,不能的话输出Impossible
网上看到一个BFS思想的解法,思想:从高位往地位组合,最高位是1,或者是2,对n取模不满足要求,那么继续往1,2后面添加新数,并且记录产生的新数取模的结果,不满足的话继续添加,先添加1并判断取模是否满足要求,不满足再添加2,知道满足要求,用struct数组模拟队列,记录首位两个指针,这样做是因为需要记录每个点的父节点,这样才能往回回复找到每一位上的数; 当然在添加新数的过程中,如果一个取模的结果已经计算过了,那么就不要再往队列里面添加了,直到头指针不再满足小于尾指针!
不能按一位一位的DFS,因为有些位置放置1,2不是同步的……
下面的代码可能有不够严谨的地方
再写一下自己对这个题目的理解,就是用一个数组模拟队列,里面存的是各种数字的组合,这种情况可以在后面添加1,2组成新的情况,但前提这种情况下的模以前诶有出现过,否则就会出现死循环或者无用 东东!
#include<iostream>
#include<cstring>
#include<cstdio>
#define N 5000002
using namespace std;
int n;
struct Node
{
int dig,mod;
int f;
}nod[N];
int l,r;
bool vis[N];
int ret;
void BFS()
{
while(l<r)
{
int tmod1=(nod[l].mod*10+1)%n;
int tmod2=(nod[l].mod*10+2)%n;
if(!vis[tmod1])
{vis[tmod1]=1;
r++;
nod[r].mod=tmod1;
nod[r].dig=1;
nod[r].f=l;
if(tmod1==0){ret=r;return ;}
}
if(!vis[tmod2])
{vis[tmod2]=1;
r++;
nod[r].mod=tmod2;
nod[r].dig=2;
nod[r].f=l;
if(tmod2==0){ret=r;return ;}
}
l++;
}
}
void out(int x)
{
if(x>0)out(nod[x].f);
else if(x==0)return;
printf("%d",nod[x].dig);
}
void init()
{
l=1;r=2;ret=0;
memset(vis,0,sizeof(vis));
vis[1]=vis[2]=1;
}
int main()
{
while(cin>>n)
{
if(n==1||n==2){cout<<n<<endl;continue;}
nod[1].dig=1;
nod[1].f=0;
nod[1].mod=1;
nod[2].dig=2;
nod[2].f=0;
nod[2].mod=2;
init();
BFS();
if(ret==0)
{
cout<<"Impossible"<<endl;continue;
}
out(ret);cout<<endl;
}
return 0;
}