zoukankan      html  css  js  c++  java
  • HDU3001 Travelling 状压DP

    哭瞎啊,每一个城市能够经过至多两次,但没有要求必须经过两次。想用 两个状压来乱搞搞。结果自觉得会T。结果 WA了,搞了一下午。没想到用三进制啊。智商捉急,參考了

    http://blog.csdn.net/lenleaves/article/details/7980955  这个博客

    每一个城市能够经过1或2次。所以三进制能够代表全部状态了。接下来处理方式类似于二进制的,仅仅是没有了位运算一些推断跟预处理有点繁琐

    方程dp[s][i] = min(dp[s][i] ,  dp[s - (s除去j剩下状态)][k] + dis[k][j]),

    因为没有固定的出发点,所以也就没有固定的终点。所以要以不论什么城市为终点的可能都要枚举到

    dp[i][j]代表i状态下以 j为终点的最小花费

    转移方程就是  : i  状态以j为终点的递推为(i状态中不经过j位置的状态下以k为终点 + k到j所需距离).


    #define MAXN 0x3f3f3f3f
    
    int n,m;
    
    int dp[100000 + 55][10 + 5];
    
    int mp[10 + 5][10 + 5];
    
    int s[59050][10 + 5];
    
    void clear() {
    	
    	for(int i=0;i<59050;i++) {
    		int tmp = i;
    		for(int j=1;j<=10;j++) {
    			s[i][j] = tmp%3;
    			tmp /= 3;
    			if(!tmp)break;
    		}
    	}
    }
    
    void init() {
    	memset(mp,0x3f3f3f3f,sizeof(mp));
    	memset(dp,0x3f3f3f3f,sizeof(dp));
    }
    
    bool input() {
    	while(scanf("%d %d",&n,&m) == 2) {
    		for(int i=0;i<m;i++) {
    			int u,v,val;
    			scanf("%d %d %d",&u,&v,&val);
    			if(val < mp[u][v]) {
    				mp[u][v] = val;
    				mp[v][u] = val;
    			}
    		}
    		return false;
    	}
    	return true;
    }
    
    void cal() {
    	if(n == 1) {puts("0");return ;}
    	int now[12];
    	now[0] = 0;
    	now[1] = 1;
    	for(int i=2;i<=11;i++)now[i] = 3 * now[i - 1];/*举出刚好仅仅过i位置的状态*/
    	for(int i=0;i<=n;i++)dp[now[i]][i] = 0;//边界值。仅仅经过i位置的状态再以i为终点耗费肯定为0
    	int ans = MAXN;
    	for(int i=0;i<now[n + 1];i++) {
    		bool flag = true;//标记推断是否訪问了全部的地方
    		for(int j=1;j<=n;j++) {/*枚举以j为终点*/
    			if(s[i][j] == 0) {flag = false;continue;}//i状态并没有经过j
    			for(int k=1;k<=n;k++) {
    				if(s[i][k] == 0)continue;/*i状态没有经过k*/
    				int tmp = i - now[j];//使得i状态中第j位置为0
    				dp[i][j] = min(dp[i][j],dp[tmp][k] + mp[k][j]);
    				/*i状态以j为终点的递推为(i状态中只是j位置的状态下以k为终点 + k到j所需距离)*/
    			}
    		}
    		if(flag)//若该状态下全部地方都訪问过了,就从以各个地方为终点的最佳方案中再取出最优的
    			for(int j=1;j<=n;j++)ans = min(ans,dp[i][j]);
    	}
    	if(ans == MAXN)puts("-1");
    	else printf("%d
    ",ans);
    }
    
    void output() {
    
    }
    
    int main () {
    	clear();
    	while(true) {
    		init();
    		if(input())return 0;
    		cal();
    		output();
    	}
    	return 0;
    }


  • 相关阅读:
    iOS6和iOS7代码的适配(5)——popOver
    es5创建对象与继承
    js学习日记-new Object和Object.create到底干了啥
    js滚动及可视区域的相关的操作
    css匹配规则及性能
    normalize.css源码分析
    css的水平居中和垂直居中总结
    js快速排序算法
    数据结构flash演示
    二叉树遍历
  • 原文地址:https://www.cnblogs.com/cynchanpin/p/6749406.html
Copyright © 2011-2022 走看看