题目链接:https://vjudge.net/problem/HDU-1565

方格取数(1)

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 9929    Accepted Submission(s): 3743

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
 
Author
ailyanlu
 
Source
 

逐行递推:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <sstream>
#include <algorithm>
using namespace std;
#define eps 0.0000001
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int mod = 1e9+;
const int maxn = +; int n, a[][], sta[maxn], val[maxn], dp[][maxn];
int tot; int cal(int r, int state)
{
int sum = ;
for(int i = ; state>; state>>=, i++)
if(state&)
sum += a[r][i];
return sum;
} int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i = ; i<=n; i++)
for(int j = ; j<=n; j++)
scanf("%d",&a[i][j]); tot = ;
for(int i = ; i<(<<n); i++)
if((i&(i<<))==)
sta[++tot] = i; memset(dp, , sizeof(dp));
for(int r = ; r<=n; r++)
{
for(int j = ; j<=tot; j++)
for(int k = ; k<=tot; k++)
{
if((sta[j]&sta[k])==)
dp[r][j] = max(dp[r][j], dp[r-][k]+ cal(r,sta[j]));
}
} int ans = ;
for(int i = ; i<=tot; i++)
if(dp[n][i]>ans)
ans = max(ans, dp[n][i]); printf("%d\n",ans);
}
return ;
}

逐格递推(轮廓线更新):

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int MOD = 1e9+;
const int MAXN = 1e5;
const int HASH = 1e4; int n, val[][], dp[][<<]; int main()
{
while(scanf("%d", &n)!=EOF)
{
for(int i = ; i<n; i++)
for(int j = ; j<n; j++)
scanf("%d", &val[i][j]); int cur = ;
for(int s = ; s<(<<n); s++)
dp[cur][s] = -INF;
dp[cur][] = ; for(int i = ; i<n; i++)
for(int j = ; j<n; j++)
{
memset(dp[cur^], , sizeof(dp[cur^]));
for(int s = ; s<(<<n); s++)
{
bool hav_up = s&(<<j);
bool hav_left = false;
if(j) hav_left = s&(<<(j-)); if(!hav_up && !hav_left)
{
dp[cur^][s^(<<j)] = max(dp[cur^][s^(<<j)], dp[cur][s]+val[i][j]); //取
dp[cur^][s] = max(dp[cur^][s], dp[cur][s]); //不取
}
//由于相邻的格子已经去了,故此格子不能取
else if(hav_left && !hav_up)
dp[cur^][s] = max(dp[cur^][s], dp[cur][s]);
else if(!hav_left && hav_up)
dp[cur^][s^(<<j)] = max(dp[cur^][s^(<<j)], dp[cur][s]);
else
dp[cur^][s^(<<j)] = max(dp[cur^][s^(<<j)], dp[cur][s]);
}
cur ^= ;
} int ans = ;
for(int s = ; s<(<<n); s++)
ans = max(ans, dp[cur][s]);
printf("%d\n", ans);
}
}

简化后:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int MOD = 1e9+;
const int MAXN = 1e5;
const int HASH = 1e4; int n, val[][], dp[][<<]; int main()
{
while(scanf("%d", &n)!=EOF)
{
for(int i = ; i<n; i++)
for(int j = ; j<n; j++)
scanf("%d", &val[i][j]); int cur = ;
for(int s = ; s<(<<n); s++)
dp[cur][s] = -INF;
dp[cur][] = ; for(int i = ; i<n; i++)
for(int j = ; j<n; j++)
{
memset(dp[cur^], , sizeof(dp[cur^]));
for(int s = ; s<(<<n); s++)
{
int up = s&(<<j);
int left = ;
if(j) left = s&(<<(j-)); dp[cur^][s^up] = max(dp[cur^][s^up], dp[cur][s]); //不取. (异或功能强大)
if(!up && !left) //取,前提是相邻格没有取
dp[cur^][s^(<<j)] = max(dp[cur^][s^(<<j)], dp[cur][s]+val[i][j]);
}
cur ^= ;
} int ans = ;
for(int s = ; s<(<<n); s++)
ans = max(ans, dp[cur][s]);
printf("%d\n", ans);
}
}

轮廓线更新 + 哈希表:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int MOD = 1e9+;
const int MAXN = 1e5;
const int HASH = 1e4; int n, val[][]; struct
{
int size, head[HASH], next[MAXN];
int state[MAXN], sum[MAXN]; void init()
{
size = ;
memset(head, -, sizeof(head));
} void insert(int status, int Sum)
{
int u = status%HASH;
for(int i = head[u]; i!=-; i = next[i])
{
if(state[i]==status)
{
sum[i] = max(sum[i], Sum);
return;
}
}
state[size] = status; //头插法
sum[size] = Sum;
next[size] = head[u];
head[u] = size++;
} }Hash_map[]; int main()
{
while(scanf("%d", &n)!=EOF)
{
for(int i = ; i<n; i++)
for(int j = ; j<n; j++)
scanf("%d", &val[i][j]); int cur = ;
Hash_map[cur].init();
Hash_map[cur].insert(, );
for(int i = ; i<n; i++)
for(int j = ; j<n; j++)
{
Hash_map[cur^].init();
for(int k = ; k<Hash_map[cur].size; k++)
{
int status = Hash_map[cur].state[k];
int Sum = Hash_map[cur].sum[k]; int up = status&(<<j);
int left = ;
if(j) left = status&(<<(j-)); Hash_map[cur^].insert(status^up, Sum); //不取
if(!up && !left) //取,前提是相邻的格子没有取
Hash_map[cur^].insert(status^(<<j), Sum+val[i][j]);
}
cur ^= ;
} int ans = ;
for(int k = ; k<Hash_map[cur].size; k++)
ans = max(ans, Hash_map[cur].sum[k]);
printf("%d\n", ans);
}
}

二分图点带权最大独立集(最小割最大流):

HDU1569 方格取数(2)

HDU1565 方格取数(1) —— 状压DP or 插头DP(轮廓线更新) or 二分图点带权最大独立集(最小割最大流)的更多相关文章

  1. HDU 1565 - 方格取数(1) - [状压DP][网络流 - 最大点权独立集和最小点权覆盖集]

    题目链接:https://cn.vjudge.net/problem/HDU-1565 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32 ...

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

    <题目链接> 题目大意: 给出一些数字组成的n*n阶矩阵,这些数字都在[10,99]内,并且这个矩阵的  3<=n<=15,从这个矩阵中随机取出一些数字,在取完某个数字后,该数 ...

  3. HDU1565 方格取数 &&uva 11270 轮廓线DP

    方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  4. Hdu-1565 方格取数(1) (状态压缩dp入门题

    方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

  5. HDU-1565 方格取数(1)

    http://acm.hdu.edu.cn/showproblem.php?pid=1565 方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Me ...

  6. HDU1565 方格取数1(构图+网络流最大独立集合)

    题目大意:给你一个n*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大. 解题思路:最大点 ...

  7. HDU1569 方格取数(2) —— 二分图点带权最大独立集、最小割最大流

    题目链接:https://vjudge.net/problem/HDU-1569 方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory L ...

  8. HDU1565 方格取数(1)(状态压缩dp)

    题目链接. 分析: 说这题是状态压缩dp,其实不是,怎么说呢,题目数据太水了,所以就过了.手动输入n=20的情况,超时.正解是网络流,不太会. A这题时有个细节错了,是dp[i][j]还是dp[i][ ...

  9. HDU1565方格取数

    典型的状态压缩DP问题.第i行的取法只受到第i-1行的影响.首先每一行的取法要相容(不能有两个相邻),然后相邻行之间也要相容.将每一个格子看做两种状态,1表示取,0表示不取.这样每一行就是一个01串, ...

随机推荐

  1. 使用Jackson在Java中处理JSON

    在工作中实际使用到Java处理JSON的情况,且有很大部分都使用的是开源工具Jackson实现的. 一.入门 Jackson中有个ObjectMapper类很是实用,用于Java对象与JSON的互换. ...

  2. hdu 1166 树状数组(线段树)

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  3. Count on a tree(bzoj 2588)

    Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始 ...

  4. Java面试题集(二)

    51.设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1,写出程序.  以下程序使用内部类实现线程,对j增减的时候没有考虑顺序问题. public class ThreadTest1 ...

  5. Ubuntu 安装PostgreSQL

    安装最新版: sudo apt-get install postgresql 安装完成后,默认会: (1)创建名为"postgres"的Linux用户 (2)创建名为"p ...

  6. c++ 高效并发编程

    高效并发编程 并发编程的基本模型包括,通过消息机制来管理运行顺序的message passing, 通过互斥保护共享的shared memory. 线程同步的基本原则 最低限度共享变量,考虑使用imm ...

  7. 洛谷P1352 没有上司的舞会

    题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri, ...

  8. mysql 5.7版本目录无data文件夹的解决办法

    安装mysql 5.7+版本时,若发现因根目录下,缺少data文件夹的情况, ***请不要去拷贝其他版本的data文件夹!*** 因为此操作会出现很多潜在问题:比如我遇到的执行show variabl ...

  9. android 文件读取(assets)

    assets文件夹资源的访问        assets文件夹里面的文件都是保持原始的文件格式,需要用AssetManager以字节流的形式读取文件.       1. 先在Activity里面调用g ...

  10. zedboard中OLED源码

    #include <stdio.h> #include "platform.h" #include "xil_types.h" #include & ...