uva 10944 Nuts for nuts..(状压dp)

题意:一幅地图中给出松鼠起点,各坚果的信息,求松鼠收集所有坚果并返回起点的最小步数;

思路:

用二进制数表示坚果的收集状态,0表示未收集,1已收集;mm[i][j]表示节点i和j的相对距离;f[i][j]表示在收集状态为j是收集i的最小步数;

显然,收集每颗坚果的最小步数为f[i][2的(i-1)次方]=mm[0][i];

递增枚举状态值i,状态i中最后被收集的坚果j,枚举i外的坚果k。

f[k][i+1<<(k-1)]=min( f[k][i+1<<(k-1)],f[j][i]+mm[j][k]);

所有坚果收集后,若最后一颗为i,则到i的最小步数为f[i][1<<(n)-1],加上返回起点的步数map[0][i],找到最少步数;

ans=min(f[i][1<<(n)-1]+mm[0][i]);(枚举i)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define inf (1<<20)
#define N 30
#define M 65536
using namespace std;
int f[N][M];
char s[N];
int mm[N][N];
int x[N],y[N];
int num,n,m,ans,maxz;
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        num=0;
        for(int i=0;i<n;i++)
        {
            scanf("%s",s);
            for(int j=0;j<m;j++)
            {
                if(s[j]==‘#‘){
                    x[++num]=i;
                    y[num]=j;//坚果位置
                }
                else if(s[j]==‘L‘){
                    x[0]=i;y[0]=j;//当前位置
                }
            }
        }
        if(!num){
            printf("0\n");continue;
        }
        for(int i=0;i<=num;i++)
            for(int j=0;j<=num;j++)
            mm[i][j]=max(abs(x[i]-x[j]),abs(y[i]-y[j]));//计算节点间相对距离的矩阵
        maxz=(1<<num)-1;
        for(int i=0;i<=maxz;i++){
            for(int j=0;j<=num;j++)
                f[j][i]=inf;
        }
        for(int i=1;i<=num;i++) f[i][1<<(i-1)]=mm[0][i];//只收集第i个坚果的步数
        for(int i=0;i<maxz;i++)  //枚举当前坚果被收集的状态
        {
            for(int j=1;j<=num;j++) if(i&(1<<(j-1)))//枚举最后被收集的坚果j
                for(int k=1;k<=num;k++)  //枚举i状态外的坚果k,调整k被收集的最优步数
                if(!(i&(1<<(k-1)))) f[k][i+(1<<(k-1))]=min(f[k][i+(1<<(k-1))],f[j][i]+mm[j][k]);
        }
        ans=inf;
        for(int i=1;i<=num;i++)  //枚举最后被收集的坚果(返回‘L’位置的最少步数)i,调整最优步数
            ans=min(ans,f[i][maxz]+mm[i][0]);
        printf("%d\n",ans);
    }
    return 0;
}
时间: 2024-07-28 20:14:21

uva 10944 Nuts for nuts..(状压dp)的相关文章

UVA 10817 Headmaster&#39;s Headache 状压DP

记录两个状态S1,S2分别记录哪些课程被1个人教过或2个人教过,然后记忆化搜索 UVA - 10817 Headmaster's Headache Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description Problem D: Headmaster's Headache Time limit: 2 seconds The headmaster of Spr

uva 11825 Hackers&#39; Crackdown (状压dp,子集枚举)

题目链接:uva 11825 题意: 你是一个黑客,侵入了n台计算机(每台计算机有相同的n种服务),对每台计算机,你可以选择终止一项服务,则他与其相邻的这项服务都终止.你的目标是让更多的服务瘫痪(没有计算机有该项服务). 思路:(见大白70页,我的方程与大白不同) 把n个集合P1.P2.Pn分成尽量多的组,使得每组中所有集合的并集等于全集,这里的集合Pi是计算机i及其相邻计算机的集合,用cover[i]表示若干Pi的集合S中所有集合的并集,dp[s]表示子集s最多可以分成多少组,则 如果cove

UVa 1252 - Twenty Questions(状压DP)

链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3693 题意: 有n(n≤128)个物体,m(m≤11)个特征.每个物体用一个m位01串表示,表示每个特征是具备还是不具备.我在心里想一个物体(一定是这n个物体之一),由你来猜.你每次可以询问一个特征,然后我会告诉你:我心里的物体是否具备这个特征.当你确定答案之后,就把答案告诉我(告

UVa 1412 - Fund Management(状压DP + 预处理)

链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4158 题意: 你有c(0.01≤c≤1e8)美元现金,但没有股票.给你m(1≤m≤100)天时间和n(1≤n≤8)支股票供你买卖,要求最后一天结束后不持有任何股票,且剩余的钱最多.买股票不能赊账,只能用现金买.已知每只股票每天的价格(0.01-999.99.单位是美元/股)与参数s

uva 11825 Hackers&amp;#39; Crackdown (状压dp,子集枚举)

题目链接:uva 11825 题意: 你是一个黑客,侵入了n台计算机(每台计算机有同样的n种服务),对每台计算机,你能够选择终止一项服务,则他与其相邻的这项服务都终止.你的目标是让很多其它的服务瘫痪(没有计算机有该项服务). 思路:(见大白70页,我的方程与大白不同) 把n个集合P1.P2.Pn分成尽量多的组,使得每组中全部集合的并集等于全集,这里的集合Pi是计算机i及其相邻计算机的集合,用cover[i]表示若干Pi的集合S中全部集合的并集,dp[s]表示子集s最多能够分成多少组,则 假设co

(状压dp)uva 10817 Headmaster&#39;s Headache

题目地址 1 #include <bits/stdc++.h> 2 typedef long long ll; 3 using namespace std; 4 const int MAX=1e5+5; 5 const int INF=1e9; 6 int s,m,n; 7 int cost[125]; 8 //char sta[MAX]; 9 string sta; 10 int able[125]; 11 int dp[125][1<<8][1<<8]; 12 in

【UVa】Headmaster&#39;s Headache(状压dp)

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1758 晕....状压没考虑循环方向然后错了好久.. 这点要注意...(其实就是01背包变成了完全背包QAQ 我们将课程拆成两个点,然后状压 那么答案就是(1<<(s<<1))-1 转移就不说了,,,,,太简单.. #include <cstdio> #in

UVA - 10817 Headmaster&#39;s Headache (状压dp+记忆化搜索)

题意:有M个已聘教师,N个候选老师,S个科目,已知每个老师的雇佣费和可教科目,已聘老师必须雇佣,要求每个科目至少两个老师教的情况下,最少的雇佣费用. 分析: 1.为让雇佣费尽可能少,雇佣的老师应教他所能教的所有科目. 2.已聘老师必须选,候选老师可选可不选. 3.dfs(cur, subject1, subject2)---求出在当前已选cur个老师,有一个老师教的科目状态为 subject1,有两个及以上老师教的科目状态为 subject2的情况下,最少的雇佣费用. dp[cur][subje

UVa 10817 (状压DP + 记忆化搜索) Headmaster&#39;s Headache

题意: 一共有s(s ≤ 8)门课程,有m个在职教师,n个求职教师. 每个教师有各自的工资要求,还有他能教授的课程,可以是一门或者多门. 要求在职教师不能辞退,问如何录用应聘者,才能使得每门课只少有两个老师教而且使得总工资最少. 分析: 因为s很小,所以可以用状态压缩. dp(i, s1, s2)表示考虑了前i个人,有一个人教的课程的集合为s1,至少有两个人教的集合为s2. 在递归的过程中,还有个参数s0,表示还没有人教的科目的集合. 其中m0, m1, s0, s1, s2的计算用到位运算,还

UVA 11825 Hackers&#39; Crackdown 状压DP

感觉白书上的做法很神! 首先状压表示电脑之间的联通关系,然后预处理出所有关闭电脑的组合达到的状态,然后枚举每个状态并且枚举每个状态的所有子集,之后无脑递推就木有了. 关于枚举一个状态所有子集的小技巧:假设当前状态是S0 有 for s = s0; s != 0; s =  (s - 1) & s0 #include <cstdio> #include <cstring> #include <iostream> #include <map> #incl