zoukankan      html  css  js  c++  java
  • UVA10944 Nuts for nuts..(状压dp)

    比较经典的(TSP)问题

    题目
    题意:松鼠位于(L)点,需要采集所有#点的松果,最后返回(L)点,问此过程的最短距离(松鼠有8种转移方式,即上下左右+对角线1个单位)

    思路:一看此题就是和售货员的难题如出一辙,只是输入方法不一样,如果做过的可以直接套版转化
    用二进制数表示坚果的收集状态,(0)表示未收集,(1)已收集;(dis)[(i)][(j)]表示节点(i)(j)的相对距离;(f)[(i)][(j)]表示在收集状态为(j)是收集(i)的最小步数;
    显然,收集每颗坚果的最小步数为(f)[(i)][(2^{i-1})]=(dis)[(0)][(i)];
    递增枚举状态值(i),状态(i)中最后被收集的坚果(j),枚举(i)外的坚果(k)
    (f)[(k)][(i)+(1)<<((k)-(1))] = (min)((f)[(k)][(i)+(1)<<((k)-(1))], (f)[(j)][(i)] + (dis)[(j)][(k)]);
    所有坚果收集后,若最后一颗为(i),则到(i)的最小步数为(f)[(i)][(1)<<((n))-(1)],加上返回起点的步数(map)[(0)][(i)],找到最少步数;
    (ans)=(min)((f)[(i)][(1)<<((n))-(1)]+(dis)[(0)][(i)]);(枚举(i))
    本题数据范围可能有误,建议数组稍微开大一点

    #include<stdio.h>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define inf 0x3f3f3f3f
    using namespace std;
    
    int n,m;const int MAXN = 30;
    char map[MAXN][MAXN];int u;int dis[MAXN][MAXN];
    int l[MAXN];int f[MAXN][1<<20];
    
    struct edge{
    	int i,j;
    }e;edge nut[MAXN];
    
    inline void init(){
    	getchar();
    	for(int i=1;i<=n;++i){
    		for(int j=1;j<=m;++j){
    			scanf("%c",&map[i][j]);
    			if(map[i][j] == '#'){
    				e.i = i;e.j = j;
    				nut[++u] = e;
    			}
    			if(map[i][j] == 'L'){
    				e.i = i;e.j = j;
    				nut[1] = e;
    			}
    		}
    		getchar();
    	}
    }
    
    inline void work(){
    	for(int i=1;i<=u;++i){
    		for(int j=i+1;j<=u;++j){
    			dis[i][j] = dis[j][i] = max(abs(nut[i].i - nut[j].i) , abs(nut[i].j - nut[j].j));
    		}
    	}
    }
    
    inline void get(){
    	memset(f,inf,sizeof f);
        f[1][1]=0;int p=(1<<u);
        for(int i=0;i<p;++i){
            for(int j=1;j<=u;++j){
                if(i&l[j]){
                    for(int k=1;k<=u;++k){
                        if(!(i&l[k])){
                            f[k][i|l[k]] = min(f[k][i|l[k]],f[j][i] + dis[j][k]);
                        }
                    }
                }
            }
        }
    }
    
    inline void clear(){
    	u = 1;
    	memset(f,0,sizeof f);
    	memset(dis,0,sizeof dis);
    	memset(l,0,sizeof l);
    }
    
    int main(){
    	while(~scanf("%d%d",&n,&m)){
    		clear();
    		init();
    		work();
    		for(int i=1;i<=u;++i) l[i] = (1<<i-1);
    		get();
    		int ans=inf;
        	for(int i=1;i<=u;++i){
            	ans = min(ans,f[i][(1<<u)-1] + dis[i][1]);
        	}
        	printf("%d
    ",ans);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    谈谈 rm -rf * 后的几点体会(年轻人得讲码德)
    shell读取文档中的命令并逐行执行
    被踢出工作群聊后的若干反思
    units命令单位转换
    想买保时捷的运维李先生学Java性能之 垃圾收集器
    想买保时捷的运维李先生学Java性能之 垃圾收集算法
    想买保时捷的运维李先生学Java性能之 生存与毁灭
    想买保时捷的运维李先生 求救求救求救求救
    想买保时捷的运维李先生学Java性能之 运行时数据区域
    想买保时捷的运维李先生学Java性能之 JIT即时编译器
  • 原文地址:https://www.cnblogs.com/lajioj/p/9318673.html
Copyright © 2011-2022 走看看