【luogu P1879】【jzoj 7199】Corn Fields G / 又是他Farmer John / 玉米田(加强版)(状压DP)(轮廓线DP)

本文主要是介绍【luogu P1879】【jzoj 7199】Corn Fields G / 又是他Farmer John / 玉米田(加强版)(状压DP)(轮廓线DP),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Corn Fields G / 又是他Farmer John / 玉米田(加强版)

题目链接:luogu P1879 / jzoj 7199

题目大意

给你一个 n*m 的矩阵,有一些位置可以选放不放东西。
然后规定一个东西旁边四个位置不能有东西。
问你有多少种放的方案。

思路

看到这个大小,我们考虑状压 DP。
不难列出 2 n + m 2^{n+m} 2n+m 的式子,然后就能过 luogu 的。

但是 jzoj 的是加强版,就会 TLE。
我们考虑优化,写轮廓线 DP。
轮廓线 DP 大概就是你设 f i , j , k f_{i,j,k} fi,j,k 就是处理到 i , j i,j i,j 的位置,轮廓线状态是 k k k 的方案数。
处理到时什么意思呢?
在这里插入图片描述
这个就是处理到 3 , 2 3,2 3,2, 就相当于假设你要看 4 , 2 4,2 4,2 的位置,那能影响它的就 3 , 2 3,2 3,2 4 , 1 4,1 4,1。(后面的我们先不管)那我们就只需要关心每列最小面的值,状态个数就由 2 n + m 2^{n+m} 2n+m 变成 2 n / 2 m 2^n/2^m 2n/2m
(虽然在这道题中我是竖着来的,不过是同一个道理)

然后就转移,先看你原来状态的要看的位置,如果有 1 1 1 就只能不选。
然后否则就是可以选可以不选,自己转移一下就可以了。
(不会转移?自己看代码去)

然后复杂度啊就是 O ( n m 2 m ) O(nm2^{m}) O(nm2m) 加点 O2 就可以过掉 jzoj。

代码

#pragma GCC optimize(2)#include<cstdio>
#include<cstring>
#define mo 100000000using namespace std;bool a[21][21];
int n, m, now, re;
int f[2][530001], ans;
char c;int read() {re = 0;c = getchar();while (c < '0' || c > '9') c = getchar();while (c >= '0' && c <= '9') {re = (re << 3) + (re << 1) + c - '0'; c = getchar();}return re;
}int main() {
//	freopen("cowfood.in", "r", stdin);
//	freopen("cowfood.out", "w", stdout);n = read(); m = read();for (int i = 1; i <= n; i++)for (int j = 0; j < m; j++)a[i][j] = read();f[0][0] = 1; now = 0; for (int i = 1; i <= n; i++)for (int j = 0; j < m; j++) {now ^= 1;for (int k = 0; k < (1 << m); k++) f[now][k] = 0;for (int k = 0; k < (1 << m); k++) {int up = (1 << j) & k, lft = (j == 0 ? 0 : (1 << (j - 1)) & k);if (i == 1 && up) continue;//出现非法情况if (j == 0 && lft) continue;if (up) {//只能不选f[now][k ^ (1 << j)] += f[now ^ 1][k];if (f[now][k ^ (1 << j)] > mo) f[now][k ^ (1 << j)] -= mo;continue;//注意这里原本是选的,要变成不选,所以要疑惑}if (lft || !a[i][j]) {//这里也是只能不选,但原本就是不选f[now][k] += f[now ^ 1][k];if (f[now][k] > mo) f[now][k] -= mo;continue;}//可以选也可以不选f[now][k] += f[now ^ 1][k];if (f[now][k] > mo) f[now][k] -= mo;f[now][k ^ (1 << j)] += f[now ^ 1][k];if (f[now][k ^ (1 << j)] > mo) f[now][k ^ (1 << j)] -= mo;}}for (int i = 0; i < (1 << m); i++)ans = (ans + f[now][i]) % mo;printf("%d", ans);fclose(stdin);fclose(stdout);return 0;
}

这篇关于【luogu P1879】【jzoj 7199】Corn Fields G / 又是他Farmer John / 玉米田(加强版)(状压DP)(轮廓线DP)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/413807

相关文章

hdu4826(三维DP)

这是一个百度之星的资格赛第四题 题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=500 题意:从左上角的点到右上角的点,每个点只能走一遍,走的方向有三个:向上,向下,向右,求最大值。 咋一看像搜索题,先暴搜,TLE,然后剪枝,还是TLE.然后我就改方法,用DP来做,这题和普通dp相比,多个个向上

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

hdu4865(概率DP)

题意:已知前一天和今天的天气概率,某天的天气概率和叶子的潮湿程度的概率,n天叶子的湿度,求n天最有可能的天气情况。 思路:概率DP,dp[i][j]表示第i天天气为j的概率,状态转移如下:dp[i][j] = max(dp[i][j, dp[i-1][k]*table2[k][j]*table1[j][col] )  代码如下: #include <stdio.h>#include

usaco 1.1 Broken Necklace(DP)

直接上代码 接触的第一道dp ps.大概的思路就是 先从左往右用一个数组在每个点记下蓝或黑的个数 再从右到左算一遍 最后取出最大的即可 核心语句在于: 如果 str[i] = 'r'  ,   rl[i]=rl[i-1]+1, bl[i]=0 如果 str[i] = 'b' ,  bl[i]=bl[i-1]+1, rl[i]=0 如果 str[i] = 'w',  bl[i]=b

uva 10154 DP 叠乌龟

题意: 给你几只乌龟,每只乌龟有自身的重量和力量。 每只乌龟的力量可以承受自身体重和在其上的几只乌龟的体重和内。 问最多能叠放几只乌龟。 解析: 先将乌龟按力量从小到大排列。 然后dp的时候从前往后叠,状态转移方程: dp[i][j] = dp[i - 1][j];if (dp[i - 1][j - 1] != inf && dp[i - 1][j - 1] <= t[i]

uva 10118 dP

题意: 给4列篮子,每次从某一列开始无放回拿蜡烛放入篮子里,并且篮子最多只能放5支蜡烛,数字代表蜡烛的颜色。 当拿出当前颜色的蜡烛在篮子里存在时,猪脚可以把蜡烛带回家。 问最多拿多少只蜡烛。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cs

uva 10069 DP + 大数加法

代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>#include <cl

uva 10029 HASH + DP

题意: 给一个字典,里面有好多单词。单词可以由增加、删除、变换,变成另一个单词,问能变换的最长单词长度。 解析: HASH+dp 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#inc

XTU 1233 n个硬币连续m个正面个数(dp)

题面: Coins Problem Description: Duoxida buys a bottle of MaiDong from a vending machine and the machine give her n coins back. She places them in a line randomly showing head face or tail face o

dp算法练习题【8】

不同二叉搜索树 96. 不同的二叉搜索树 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。 示例 1: 输入:n = 3输出:5 示例 2: 输入:n = 1输出:1 class Solution {public int numTrees(int n) {int[] dp = new int