HDU1565—方格取数(1)——状压DP

来源:互联网 发布:啥软件机票便宜 编辑:程序博客网 时间:2024/06/05 09:06

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

本题思路::肯定是状态压缩的DP。把每一种可能的状态存放在 mp 数组中,共有tot种状态。用 dp 二维数组记录最大值。其中dp[ i ][ j ]表示到第 i 行 j 状态的最大值。状态转变方程为dp[ i ][ j ] = max(dp[ i ][ j ] , dp[ i-1 ][ k ] + sum[ j ]); 其中dp[ i - 1 ][ k ]表示第  i - 1 行 k  状态 ,sum 为 i 行 j 状态的总和。详情看代码。
//这道题的关键在于时间和空间复杂度思路还是比较简单//第一次::把每一个状态都记录在数组中,超了空间//第二次::把不可能的状态踢掉,超了时间//第三次::看了网上的题解,发现可以把当前行,和上一行换位置,节省了大量时间,过掉了#include <iostream>#include <sstream>#include <ios>#include <iomanip>#include <functional>#include <algorithm>#include <vector>#include <string>#include <list>#include <queue>#include <deque>#include <stack>#include <set>#include <map>#include <cstdio>#include <cstdlib>#include <cmath>#include <cstring>#include <climits>#include <cctype>using namespace std;#define XINF INT_MAX#define INF 0x3FFFFFFF#define MP(X,Y) make_pair(X,Y)#define PB(X) push_back(X)#define REP(X,N) for(int X=0;X<N;X++)#define REP2(X,L,R) for(int X=L;X<=R;X++)#define DEP(X,R,L) for(int X=R;X>=L;X--)#define CLR(A,X) memset(A,X,sizeof(A))#define IT iteratortypedef long long ll;typedef pair<int,int> PII;typedef vector<PII> VII;typedef vector<int> VI;//const int MAXN = 10010;//#define INF 0x3FFFFFFF/********************************************************头文件*********************************************************/int mp[20000];   //曾经尝试用map,后来发现和数组功能完全相同int dp[20][20000];//可以进一步改为滚动数组可节省空间int maps[23][23];//记录值int main(){int n;while(cin>>n){memset(dp,0,sizeof(dp));REP2(i,1,n)//这里从第一行开始记录REP(j,n)//这里从第零列开始记录{    cin>>maps[i][j];}int tot = 0;//tot用来记录有多少种可能性for(int i =0;i<(1<<n);i++)//遍历每一种情况{if(i & (i << 1)) continue; //出现相邻直接过掉mp[tot++] =i;}int ans = 0;//用来记录结果for(int i = 0; i < n; i++){//遍历每一行因为从0开始,所以下面为i+1for(int j = 0; j < tot; j++){ //遍历当前行的每一种状态    int sum = 0;//用来记录当前状态第i+1行的总和    REP(l,n){                        int t = 1<<l;                        if(mp[j]&t)                            sum += maps[i+1][l];}for(int k = 0; k < tot; k++){ //遍历上一行状态if(mp[j] & mp[k]) continue; //两行之间有相邻dp[i+1][j] = max(dp[i+1][j],sum+dp[i][k]);//截止到i+1行为j状态是的最大值ans = max(ans,dp[i+1][j]);//答案应取每一个最大状态的最大值}}}cout<<ans<<endl;}return 0;}

0 0
原创粉丝点击