zoukankan      html  css  js  c++  java
  • hdu 5418 Victor and World (最短哈密顿回路)

    给你n个国家,m条路线:u_i与v_i之间的距离w_i。

    输出从1号国家出发经过每个国家至少一次再回到1号国家的最短距离。

    【官方题解】:

    我们首先需要预处理出任意两个国家之间的最短距离,因为数据范围很小,所以直接用Floyd就行了。

    之后,我们用f[S][i]表示访问国家的情况为S,当前最后访问的一个国家是i所需要的最小总油量,其中,S的二进制表示记录了访问国家的情况,S在二进制表示下的第i位(不管是从左往右还是从右往左都可以)。如果是1则表示第i个国家被访问过了,否则表示第i个国家没有被访问过。

    如dp[13][3](13=1101表示现有城市1、3、4)表示从城市1到城市3的最短路(可能经过城市4)。

    那么状态转移方程:

    f[S|(1<<i)][i]=min(f[S][j]+f[i][j]),
    其中,S这个状态不包含i城市但包含j城市。即i和j满足S&(1<<j)=1且S&(1<<i)=0。

    最开始时,除了f[1][1]是0,其他情况都是无穷大,之后先枚举S,再枚举i(我验题的时候因为这里搞反结果WA了),那么最终的答案就是

    min(f[(1<<n)-1][i]+f[i][1]),其中i∈ [2,n]。

    总复杂度为O(n^3+n^2*2^n)

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <string>
    #include <stack>
    #include <queue>
    #include <set>
    #include <map>
    typedef long long ll;
    
    using namespace std;
    
    const int inf=0x3f3f3f3f;
    const int maxn=1e6+10;
    
    int m,n;
    int g[20][20];
    int dp[maxn][20];
    
    void floyd(){
    	for(int k=1;k<=n;++k){
    		for(int i=1;i<=n;++i){
    			for(int j=1;j<=n;++j){
    				g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
    			}
    		}
    	}
    }
    
    int main()
    {
    
    	int t;
    	scanf("%d",&t);
    	while(t--){
    		memset(g,inf,sizeof g);
    
    		scanf("%d %d",&n,&m);
    		int u,v,w;
    		for(int i=0;i<m;i++){
    			scanf("%d %d %d",&u,&v,&w);
    			if(g[u][v] > w){
    				g[u][v]=g[v][u]=w;
    			}
    		}
    
    		if(n == 1){  
                cout<<0<<endl;  
                continue;  
            }  
    
    		floyd();
    		for(int i=1;i<=n;++i)g[i][i]=0;
    		
    		memset(dp,inf,sizeof dp);
    		dp[1][1]=0;
    
    
    		for(int s=1;s< (1<<n) ; ++s ){
    			for(int i=1;i<=n;++i){
    				if(s&(1<<(i-1))){//s中包含i
    					for(int j=1;j<=n;++j){
    						if( (s&(1<<(j-1)))==0 ){//s中不包含j
    							int tt= (s | (1<<(j-1)) );//tt为s包含j的状态
    							dp[tt][j]=min(dp[tt][j],dp[s][i]+g[i][j]);
    						}
    					}
    				}
    				
    			}
    		}
    		//printf("%d
    ",g[n][1] );
    		int ans=inf;
            for(int i=2;i<=n;i++)
            	ans=min(ans,dp[ (1<<n) -1 ][i]+g[i][1]);
            printf("%d
    ",ans);
    	}
    	
    }
    

      

  • 相关阅读:
    idea中如何配置tomcat
    onselectstart属性解决双击出现的蓝色区域
    (二十二)数组的最大值和最小值
    (二十一)数组的初始化
    (二十)两种数据类型的对比
    (十九)数组的内存分配
    (十八)数组概述
    (十六)函数的重载
    (十七)自定义函数
    (十五)函数的入栈和出栈
  • 原文地址:https://www.cnblogs.com/bruce27/p/4781965.html
Copyright © 2011-2022 走看看