hdu 1565 方格取数(1) (状态压缩+dp)

方格取数(1)

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 5589    Accepted Submission(s): 2123

Problem Description

给你一个n*n的格子的棋盘,每个格子里面有一个非负数。

从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大。

Input

包括多个测试实例,每个测试实例包括一个整数n 和n*n个非负数(n<=20)

Output

对于每个测试实例,输出可能取得的最大的和

Sample Input

3
75 15 21
75 15 28
34 70 5 

Sample Output

188

思路:枚举每个状态,得到最优解。枚举上下两个状态时,应判断它们之间是否矛盾,用一个二进制数可以记录每一行的一种取法,即相邻的两位的数字不能都为1,间隔取数。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define N 21
#define M 30000
int state[M];
int a[N][N];
int dp[N][M];
int n,lim;
void inti()  //得到一行能取的数的所有集合
{            //每个数组元素代表一种取法
    int i,k;
    for(i=k=0;i<=(1<<20);i++)
    {
        if(i&(i<<1))  //每个数字左移一位,若与自身相与为真
            continue; //这个数字肯定有相邻两位都为1.
        state[k++]=i; //i=1101 ,左移一位后为ii=11010 ,
    }
}
int getsum(int i,int x)  //得到该种取法的数组和
{
    int t,sum;
    t=sum=0;
    while(x)
    {
        if(x&1)          //相与为真则这个数字能取
            sum+=a[i][t];
        x>>=1;
        t++;
    }
    return sum;
}
void solve()
{
    int i,j,k;
    lim=1<<n;
    for(i=0;state[i]<lim;i++)
    {
        dp[0][i]=getsum(0,state[i]);
    }
    for(i=1;i<n;i++)         //遍历剩下的数组
    {
        for(j=0;state[j]<lim;j++) //对于每一行可取的状态
        {
            int tmp=0;
            for(k=0;state[k]<lim;k++) //找到上一行能取得最大值
            {
                if(!(state[j]&state[k]))  //相邻两行不矛盾
                    tmp=max(tmp,dp[i-1][k]);
            }
            dp[i][j]=tmp+getsum(i,state[j]);
        }
    }
    int ans=0;
    for(i=0;state[i]<lim;i++)
        ans=max(ans,dp[n-1][i]);
    printf("%d\n",ans);
}
int main()
{
    int i,j;
    inti();
    while(scanf("%d",&n)!=-1)
    {
        if(n==0)  //特判
        {
            printf("0\n");
            continue;
        }
        for(i=0;i<n;i++)
        {
            for(j=0;j<n;j++)
            {
                scanf("%d",&a[i][j]);
            }
        }
        solve();
    }
    return 0;
}
时间: 2024-10-15 15:13:40

hdu 1565 方格取数(1) (状态压缩+dp)的相关文章

HDU 1565 方格取数(1)(状压dp)

感觉这道题目的数据比较水啊,程序的时间复杂度为1711^2*20竟然也可以过掉....其他的就是状压了啊,注意需要滚动一下啊.... 方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5701    Accepted Submission(s): 2159 Problem Description 给你一个n*n的格子的棋

HDU 1565 方格取数(1) (状态压缩DP)

HDU 1565 方格取数(1) (状态压缩DP) ACM 题目地址: HDU 1565 方格取数(1) 题意: 中文. 分析: dp[i][j]表示前i行状态j的最优解. 先预处理出符合条件的数,17000+个(n在20以内). 不过感觉复杂度挺高的会T,但是却能A. 这题的正解应该是最小割,回头补下. 代码: /* * Author: illuz <iilluzen[at]gmail.com> * File: 1565_dp.cpp * Create Date: 2014-09-19 23

hdu 1565 方格取数(1)

这个题网上很多人都说用状态压缩dp来做,我就是觉得状态压缩dp有点那么理解不上啊,不过如果这个题吧相邻的两个格子连起来,那不就是求最大权独立点集吗?奋战了三天,我的第一道最大流题目终于写出来了,高兴啊! #include<map> #include<set> #include<stack> #include<queue> #include<cmath> #include<vector> #include<cstdio> #

hdu 1565 方格取数(2)(网络流之最大点权独立集)

题目链接:hdu 1565 方格取数(2) 题意: 有一个n*m的方格,每个方格有一个数,现在让你选一些数.使得和最大. 选的数不能有相邻的. 题解: 我们知道对于普通二分图来说,最大独立点集 + 最小点覆盖集 = 总点数,类似的,对于有权的二分图来说,有: 最大点权独立集 + 最小点权覆盖集 = 总点权和, 这个题很明显是要求 最大点权独立集 ,现在 总点权 已知,我们只要求出来 最小点权覆盖集 就好了,我们可以这样建图, 1,对矩阵中的点进行黑白着色(相邻的点颜色不同),从源点向黑色的点连一

网络流 [HDU 1565] 方格取数(1)

方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5961    Accepted Submission(s): 2268 Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数

HDU 1565 方格取数(1) (状态压缩 DP)

方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5779    Accepted Submission(s): 2194 Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出

hdu 2167 方格取数 【状压dp】(经典)

<题目链接> 题目大意: 给出一些数字组成的n*n阶矩阵,这些数字都在[10,99]内,并且这个矩阵的  3<=n<=15,从这个矩阵中随机取出一些数字,在取完某个数字后,该数字周围8个点都不能取,问:取得数字的最大和为多少? 解题分析: 由于对每一个数,有选和不选两种可能,分别对应状态压缩中的1和0,且 n<=15,1<<15不是非常大,因此就可以非常自然的想到状态压缩. 此题要与普通的状压dp不同的是,当某一行取某种方案时,如何求出这种取数的所有取得的数之和,

HDU 1565 方格取数(1)(状压DP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1565 Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大. Input 包括多个测试实例,每个测试实例包括一个整数n 和n*n个非负数(n<=20) Output 对于每个测试实例,输出可能取得的最大的和 Sample Input 3 75

HDU - 1565 方格取数(1) (DP)

Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大. Input 包括多个测试实例,每个测试实例包括一个整数n 和n*n个非负数(n<=20) Output 对于每个测试实例,输出可能取得的最大的和 Sample Input 3 75 15 21 75 15 28 34 70 5 Sample Output 188 思路:用dp[i][j]表示到i行时下