没有哈密瓜只有哈密顿----图论之哈密顿回路
老规矩,先来百度一下
哈密顿图(哈密尔顿图)(英语:Hamiltonian graph,或Traceable graph)是一个无向图,由天文学家哈密顿提出,由指定的起点前往指定的终点,途中经过所有其他节点且只经过一次。在图论中是指含有哈密顿回路的图,闭合的哈密顿路径称作哈密顿回路(Hamiltonian cycle),含有图中所有顶点的路径称作哈密顿路径(Hamiltonian path)。
通俗来说就是,哈密顿路径就是每个点经过且只经过一次的路径,而最终又回到起点的路径就哈密顿回路。
哈密顿路径问题在上世纪七十年代初,终于被证明是"NP完备"的。据说具有这样性质的问题,难于找到一个有效的算法。也就是说这个问题,没有实际的算法解决。
所以我们也就是简单了解一下相关定理。
(1)若图的最小度不小于顶点数的一半,则图是哈密顿图;
(2)若图中每一对不相邻的顶点的度数之和不小于顶点数,则图是哈密顿图。
(3)范定理:若图中每对距离为2的点中有一点的度数至少是图的点数的一半,则该图存在哈密尔顿圈。
哈密顿绕行世界问题HDU - 2181
20的3次方,直接暴力dfs跑一遍
1 #include<cstdio> 2 int vv[25][5],ans[25],vis[25]; 3 int m,cnt; 4 void dfs(int n,int u){ 5 ans[n]=u; 6 if(n==21){ 7 printf("%d: ",cnt++); 8 for(int i=1;i<=21;i++) printf(" %d",ans[i]); 9 printf("\n"); 10 return ; 11 } 12 for(int i=1,v;i<=3;i++){ 13 v=vv[u][i]; 14 if(!vis[v]){ 15 if(v==m&&n!=20) continue; 16 vis[v]=1; 17 dfs(n+1,v); 18 vis[v]=0; 19 } 20 } 21 } 22 int main(){ 23 for(int i=1;i<=20;i++) 24 for(int j=1;j<=3;j++){ 25 scanf("%d",&vv[i][j]); 26 for(int k=1;k<j;k++) if(vv[i][k]>vv[i][j]){ 27 int temp=vv[i][j];vv[i][j]=vv[i][k];vv[i][k]=temp; 28 } 29 } 30 while(scanf("%d",&m)&&m){ 31 for(int i=1;i<=20;i++) vis[i]=0; 32 cnt=1; 33 dfs(1,m); 34 } 35 return 0; 36 }
A sample Hamilton pathHDU - 3538
题意:求从0出发的最短哈密顿路径长度,没有就-1
暴力搜索的话21的21次方,肯定是不可能的,然后我们想一下,每个点走没走的话,那就是1或0,那我们从状态来考虑的就2的21次方-1种状态,也就全0到全1,某位有1就代表这个点走过了。
所以就成了状压dp,然后路径的话还得记录下当前最后走的点,所以dp[i][j]就是i这个状态下,最后走到的点是j的最短路径。最后就一些细节的判断。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int N=1<<21,inf=1e9+7; 5 int dp[N][25],dis[25][25],cf2[25]={1},fir[25]; 6 int main(){ 7 int n,m,nn,a,b; 8 for(int i=1;i<=21;i++) cf2[i]=cf2[i-1]<<1; 9 while(~scanf("%d%d",&n,&m)){ 10 nn=1<<n; 11 for(int i=0;i<n;i++) fir[i]=0; 12 for(int i=0;i<nn;i++) 13 for(int j=0;j<n;j++) 14 dp[i][j]=inf; 15 for(int i=0;i<n;i++) 16 for(int j=0;j<n;j++) 17 scanf("%d",&dis[i][j]); 18 for(int i=0;i<m;i++){ 19 scanf("%d%d",&a,&b); 20 if(a!=0) fir[b]|=cf2[a]; 21 } 22 dp[1][0]=0; 23 for(int i=1;i<nn;i++) 24 for(int j=0;j<n;j++){ 25 if(dp[i][j]==inf) continue; 26 for(int k=1;k<n;k++){ 27 if((i&cf2[k])!=0||(i&fir[k])!=fir[k]) continue; 28 if(dis[j][k]!=-1) dp[i+cf2[k]][k]=min(dp[i+cf2[k]][k],dp[i][j]+dis[j][k]); 29 } 30 } 31 int ans=inf; 32 for(int i=0;i<n;i++) if(ans>dp[nn-1][i]) ans=dp[nn-1][i]; 33 if(ans==inf) ans=-1; 34 printf("%d\n",ans); 35 } 36 return 0; 37 }
我太难了~给个三连吧,亲~~~