hdu1664 广搜
题意:同 poj 2283 给一个数字n,求n的倍数中,所使用不同数字最少的。例如1223含3个不同数字。如果有多个答案,取最小的。
分析:对于任意n,最多两个数字就能组成n的倍数。因为a,aa,aaa……取n+1个,则必有两个模n余数相同,相减即得n的倍数。
所以先考虑一个数字的情况,若没有n的倍数,再广搜两个数字。搜的时候要对余数判重,如果出现了相同的余数,则形成了循环。
另外搜两个数字的时候,要枚举这两个数字再搜,同时搜10个数字会爆空间。
const int M = 170000; int ans[M], pa; int a[M], p;//数字 int b[M],pre[M];//余数 前驱 int r[M];//余数判重 void check1(int *a, int p){//a[]当前答案 比ans[]小 则更新 if(pa==-1 || pa>p){ pa=0; FOR(i,0,p) ans[pa++]=a[i]; return ; } if(pa<p)return; bool flag=false; FOR(i, 0, pa) if(ans[i]!=a[i]) { if(ans[i]>a[i]) flag=true; break; } if(flag) { pa=0; FOR(i,0,p) ans[pa++]=a[i]; } } bool bfs1(int n){//一个数字 pa = -1; FOE(i, 1, 9) { p=0; memset(r, 0, sizeof(int)*(n+3)); int t = 0; FOR(j, 1, M){ t = (t*10+i)%n; a[p++] = i; if(t==0) {check1(a,p);break;} else if(r[t]) break; else r[t]=1; } } if(pa!=-1){ FOR(i, 0, pa)cout<<ans[i];cout<<endl; return true; } return false; } int aa[M], pp; void check2(int p){ pp=0; while(1){ aa[pp++]=a[p]; if(pre[p]==-1)break; p=pre[p]; } FOE(i,0,(pp-1)/2) swap(aa[i],aa[pp-i-1]); check1(aa,pp); } queue<int> q; void bfs2(int i,int j,int n){//两个数字 memset(r, 0, sizeof(int)*(n+3)); while(!q.empty())q.pop(); p=0; if(i){ a[p]=i; b[p]=i%n; pre[p]=-1; r[b[p]]=1; q.push(p); p++; } a[p]=j; b[p]=j%n; pre[p]=-1; r[b[p]]=1; q.push(p); p++; while(!q.empty()){ int t=q.front(); q.pop(); a[p]=i; b[p]=(b[t]*10+i)%n; pre[p]=t; if(b[p]==0) check2(p); else if(r[b[p]]==0){r[b[p]]=1; q.push(p); p++;} a[p]=j; b[p]=(b[t]*10+j)%n; pre[p]=t; if(b[p]==0) check2(p); else if(r[b[p]]==0){r[b[p]]=1; q.push(p); p++;} } } int main(){ #ifndef ONLINE_JUDGE //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); #endif int n; while(cin>>n, n){ if( bfs1(n) ) continue; FOE(i, 1, 9) FOE(j, 0, 9) if(i>j) bfs2( j, i, n ); FOR(i, 0, pa) cout<<ans[i]; cout<<endl; } return 0; }