假设a,aa,aaa……一直下去,对n取模,一定会出现循环,也就是会有aaaa…aaa和aaa…aa对n取模相同,那么把他们相减得到aaaa…0000,则只出现了2个数字得到了n的倍数。这种方法虽然不是最优,但保证了不同的数不会超过2种,所以可以直接搜索。
枚举所有组合(首先枚举只出现1种数字,再枚举出现2种的),然后搜索就够了,判重时用余数判重。
注意得到答案后要进行字典序比较。
此题不用把字符串保存在队列中,直接维护父亲节点的路径和信息,然后最后一次递归取出。
#include<iostream> #include<cstdlib> #include<cstring> #include<cmath> #include<cstdio> #include<algorithm> #include<queue> #include<string> using namespace std; #define INF 0x3f3f3f3f #define M 10001 int fa[M],pa[M],vis[M]; char s[M]; int top; int anstop; char ans[M]; char tmp[M]; int n,m; void print(int k) { if(k==0) return; print(fa[k]); s[top++]=pa[k]; } void cmp() { if(anstop<top) return; if(anstop>top) { for(int i=0;i<top;i++) ans[i]=s[i]; anstop=top; } for(int i=0;i<top;i++) { if(ans[i]>s[i]) { for(int j=i;j<top;j++) ans[j]=s[j]; anstop=top; return; } if(ans[i]<s[i]) return; } } queue<int> Q; bool bfs(int k1,int k2) { top=0; if(k1+k2==0) return false; while(!Q.empty()) Q.pop(); memset(vis,0,sizeof(vis)); fa[0]=-1; Q.push(0); while(!Q.empty()) { int t=Q.front();Q.pop(); if(t||k1){ int f=(t*m+k1)%n; if(!vis[f]) { vis[f]=1; fa[f]=t; pa[f]=k1+‘0‘; if(f==0) { print(fa[f]); s[top++]=pa[f]; if(anstop==0) {anstop=top;for(int i=0;i<top;i++) ans[i]=s[i];} else cmp(); return true; } Q.push(f); } } if(t||k2){ int f=(t*m+k2)%n; if(!vis[f]) { vis[f]=1; fa[f]=t; pa[f]=k2+‘0‘; if(f==0) { print(fa[f]); s[top++]=pa[f]; if(anstop==0) {anstop=top; for(int i=0;i<top;i++) ans[i]=s[i];} else cmp(); return true; } Q.push(f); } } } return false; } int main() { while(~scanf("%d%d",&n,&m)) { top=anstop=0; for(int i=1;i<m;i++) { bfs(i,i); } if(!anstop) for(int i=0;i<m;i++) { for(int j=i+1;j<m;j++) { bfs(i,j); } } for(int i=0;i<anstop;i++) { putchar(ans[i]); } puts(""); } return 0; }
hdu 4294 Multiple 搜索,布布扣,bubuko.com
原文:http://blog.csdn.net/t1019256391/article/details/21482233