HDU 2167 状压dp方格取数

题意:给出一个数表,规定取出一个数后周围的八个数都不可取,求可获得的最大数字和

思路:状态压缩dp,每一行的取数方法为状态,显然,由于取数规则的限制,可取的状态并不是

1<<size_col,而是非常有限的,我们可以预处理出状态(不超过1600个),大大降低时间复杂度,

运行时间:140ms

#include <bits/stdc++.h>
using namespace std;
int dp[16][1600],sta[1600],len,n;
int g[15][15];
void init()
{
    for(int i=0;i<(1<<15);i++)if(!(i&(i<<1))&&!(i&(i>>1)))sta[len++]=i;//预处理出所有可取状态
}

int Res[16][1600];//加个记忆化,避免重复的计算
inline int calstatus(int row,int sta,int j)//计算出row行这个状态所有数字的的sum
{
    if(Res[row][j])
        return Res[row][j];
    int res=0;
    for(int j=0;j<n;j++){
        if(sta&1)
        {
            res+=g[row][j];
        }
        sta>>=1;
    }
    return Res[row][j]=res;
}
int main()
{
    init();
    while (n=0,~scanf("%d",&g[0][n++]))
    {
        memset(Res,0,sizeof(Res));
        memset(dp,0, sizeof(dp));//初始化
        //坑爹输入部分
        while (true)
        {
            scanf("%d",&g[0][n++]);
            if(getchar()==‘\n‘)break;
        }
        for(int i=1;i<n;i++)
            for(int j=0;j<n;j++)scanf("%d",&g[i][j]);
        //第一行预处理
        for(int i=0;i<n;i++)
            for(int j=0;j<len&&sta[j]<(1<<n);j++)dp[0][j]=calstatus(0,sta[j],j);
        int ans=0;
        for(int i=1;i<n;i++)
        {
            for(int j=0;j<len&&sta[j]<(1<<n);j++)
            {
                for(int k=0;k<len&&sta[k]<(1<<n);k++)
                    if(!(sta[k]&(sta[j]<<1))&&!(sta[k]&(sta[j]>>1))&&!(sta[k]&sta[j])){//左移右移与不移,两个状态都不冲突,进行状态转移
                        dp[i][k]=max(dp[i][k],dp[i-1][j]+calstatus(i,sta[k],k));
                        ans=max(ans,dp[i][k]);
                    }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/xusirui/p/9741387.html

时间: 2024-11-05 02:28:26

HDU 2167 状压dp方格取数的相关文章

HDU 2167 状压DP

方格取数问题,给出n*n矩阵,3<n<15 求能取得的最大和,要求取某个位置的数以后,其周围的8个数字均不能再取 先预处理出来所有的可取状态,n=15时只有1597个状态,然后地推求解即可 #include "stdio.h" #include "string.h" int n,ans; int b[21],a[21][21],s[1700]; int dp[21][70001],sum[21][70001]; int Max(int a,int b)

hdu 4906 状压dp

/* ID: neverchanje PROG: LANG: C++11 */ #include<vector> #include<iostream> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<cstdio> #include<set> #include<queue> #includ

HDU 4284 状压dp+spfa堆优化

题意: 给定n个点 m条无向边 d元. 下面m行表示每条边 u<=>v 以及花费 w 下面top 下面top行 num c d 表示点标为num的城市 工资为c 健康证价格为d 目标是经过给定的top个城市,当到达该城市时,必须马上购买该城市的健康证并打工赚钱(每个城市只打工1次) 问从1城市出发,最后回到1城市,能否收集到所有的健康证 思路: 由于top很小,所以状压dp dp[i][tmp]表示当前处于i点 经过城市的状态为tmp时 身上最多的钱. 首先对dis数组floyd 跑出最短路,

HDU 4892 状压dp

[BestCoder Round #5]冠军的奖励是小米3手机一部 恭喜福州大学杨楠获得[BestCoder Round #4]冠军(iPad Mini一部) <BestCoder用户手册>下载 Defence of the Trees Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 224    Accepted Submiss

Travel(HDU 4284状压dp)

题意:给n个城市m条路的网图,pp在城市1有一定的钱,想游览这n个城市(包括1),到达一个城市要一定的花费,可以在城市工作赚钱,但前提有工作证(得到有一定的花费),没工作证不能在该城市工作,但可以走,一个城市只能工作一次,问pp是否能游览n个城市回到城市1. 分析:这个题想到杀怪(Survival(ZOJ 2297状压dp) 那个题,也是钱如果小于0就挂了,最后求剩余的最大钱数,先求出最短路和 Hie with the Pie(POJ 3311状压dp) 送披萨那个题相似. #include <

HDU 1565 状压dp

从第一行到开始,一行一行进行考虑 方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5751    Accepted Submission(s): 2180 Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的

HDU 3001 状压DP

有道状压题用了搜索被队友骂还能不能好好训练了,, hdu 3001 经典的状压dp 大概题意..有n个城市 m个道路  成了一个有向图.n<=10: 然后这个人想去旅行.有个超人开始可以把他扔到任意的一个城市..然后他就在城市之间游荡.要满足他要游玩所有的城市..并且.每个城市最多去两次.要求路程最短..如果他不能游完所有的城市,,那么..就输出-1  否则 输出最短距离 如果用搜索...不靠谱  然后用搜索,, 怎么压缩?? 用一个整型数 i 表示他现在的状态..显然一个城市是要用两位..00

hdu 3254 (状压DP) Corn Fields

poj 3254 n乘m的矩阵,1表示这块区域可以放牛,0,表示不能,而且不能在相邻的(包括上下相邻)两个区域放牛,问有多少种放牛的方法,全部不放也是一种方法. 对于每块可以放牛的区域,有放或者不放两种选择,状压DP,dp[i][j]表示第 i 行以state[j]这种状态的时候和方法取值. 具体的参考http://www.tuicool.com/articles/JVzMVj 写的很详细. 1 #include<cstdio> 2 #include<cstring> 3 #inc

HDU 6321 (状压dp)

题目大意:: 为给你n个点(n<=10,nn<=10,n) 初始时没有边相连 然后有m个操作(m<=30000m<=30000) 每次可以添加一条边或删除一条边 允许有重边 要求每次操作过后输出选这个图中不相交的k条边有多少种不同的方案 (k=1,2,3--n/2) 题目分析: n最大只有10 , 所以很容易就可以想到状压DP , 但是我在打的时候并没有想出继承状态 , 后来看了题解才略有一丝感悟: 首先一个特别容易看出的状态是每加/减一条边后的状态是由前一个状态转移过来的 : 而