| ||||
| 嗯嗯,说一下上次我想到的解法: 做一个无向图,图中节点就是 1...n 的数字,然后如果两个数字之和为素数,就在它们之间连一条边。那么上述问题就变成找出这个图中所有长度为 n 的环(也就是哈密尔顿环啦)。解这个问题可以用枚举所有环的办法,也就是找出所有的基本环,然后枚举它们的线性组合。这个是经典问题,资料比较多我就不说了。 这个算法的优势在于利用经典问题的现成算法,应该是比较优的。枚举基本环的线性组合看上去很费时间,但是考虑到我们只需要哈密尔顿环,其实搜索的时候剪枝很容易,应该会比较快。主要问题在于没有利用素数的性质。 |
| |||
| 利用限制排列生成算法解决这个问题,没有考虑到剔除对称模式,在n<=14时速度还可以。 #include <iostream> #include <iterator> #include <windows.h> using namespace std; int Prime[]={0,0,1,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1, 0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0}; void f( int n ){ int *a=new int[n+1], *l=new int[n+1], *u=new int[n+1]; int k, p, q; for( k=0; k<n; ++k ) l[k]=k+1; l[n]=0; k=1; X2: p=0; q=l[0]; X3: a[k]=q; if( !( k==1 || Prime[a[k-1]+a[k]] ) ) goto X5; else if( k==n ){ copy( a+1, a+n+1, ostream_iterator<int>(cout," ") ),cout<<endl; goto X6; } u[k]=p; l[p]=l[q]; ++k; goto X2; X5: p=q; q=l[p]; if( q!=0 ) goto X3; X6: --k; if( k==0 ) return; p=u[k], q=a[k], l[p]=q; goto X5; delete []a; delete []u; delete []l; } int main( ) { int n; cin>>n; f( n ); return 0; } |