首页 > 其他分享 >[USACO06NOV] Corn Fields G 题解

[USACO06NOV] Corn Fields G 题解

时间:2024-11-12 21:31:07浏览次数:1  
标签:状态 cnt sta int 题解 Fields USACO06NOV dp

题目链接

[USACO06NOV] Corn Fields G

题解

这是一道典型的状压dp,对于 \(M\) 行 \(N\) 列的图,由于每个点只有 \(1\) 和 \(0\) 两种状态,我们将其压缩为一个长度为 \(M\) 的数组,数组( \(g\) )的每一项 \(g_{i}\) 表示状态的二进制表示法表示的数(如 \(101\) 表示为 \(5\) ),我们预先处理 \(cnt\) 个可能的状态,将其存放在数组 \(sta\) 当中,我们在用 \(f_{i,j}\) 来表示表示第 \(i\) 行选择状态 \(j\) 的最大情况数
易得到状态转移方程式:
\( f_{i,j}= \begin{cases} f_{i,j} \\f_{i,j}+f_{i-1,k} \end{cases} \)
其中 \(k\) 表示第 \(i-1\) 行的状态为 \(sta_{k}\) ,那么对于状态 \(j\),它存在的条件是:

  • 状态 \(j\) 必须可以存在于第 \(i\) 行,即不能有原图上标记为 \(0\) 的点而状态 \(j\) 上标记为 \(1\) 的点,判断代码:
if (sta[i]&(~g[1]));
  • 状态 \(j\) 不能与第 \(i-1\) 行的状态 \(k\) 冲突,即状态 \(k\) 上为 \(1\) 的点,状态 \(j\) 上的这个点不能为 \(1\) ,判断代码:
if (sta[k]&sta[j]);
  • 同时注意一个细节,在遍历 \(k\) 时,\(k\) 也要符合第 \(i-1\) 行,即:
if (sta[k]&(~g[i-1]));

对于第一行,要单独处理,因为不存在第 \(i-1\) 行。对于最后输出的答案,要把最后一行所有可能的状态的情况数相加才行

int ans=0;
for (int i=1;i<=cnt;i++) ans+=dp[m][i];

CODE

#include<cstdio>
using namespace std;
#define P 100000000

int m,n;
int g[13];
int sta[5000];      //预处理的所有可能的状态
int dp[13][5000];   //dp[i][j]表示第i行如果选择状态j,最大情况数
int cnt;

void dfs(int s,int t){
    if (t>=n){
        sta[++cnt]=s;
        return;
    }
    dfs(s,t+1);    //当第t+1个点不选
    dfs(s+(1<<t),t+2);    //当第t+1个点选,直接跳转至t+2对t+2+1的点进行选择
}

int main(){
    scanf("%d%d",&m,&n);
    for (int i=1;i<=m;i++){
        for (int j=1;j<=n;j++){
            int tmp;
            scanf("%d",&tmp);
            g[i]=g[i]+(tmp<<(n-j));  //处理每一行的状态(转换为二进制值)
        }
    }
    dfs(0,0);   //预处理
    for (int i=1;i<=cnt;i++){
        if (sta[i]&(~g[1])) continue;   //判断状态i对于第一行是否可选
        else dp[1][i]++;                //如果可选,情况+1
    }//第一行特殊处理
    for (int i=2;i<=m;i++){
        for (int j=1;j<=cnt;j++){
            for (int k=1;k<=cnt;k++){
                if (sta[j]&(~g[i])) continue;   //判断状态i对于第i行是否可选
                if (sta[k]&(~g[i-1])) continue; //判断状态k对于第i-1行是否可选
                if (sta[k]&sta[j]) continue;    //判断状态k和状态j是否可以作为相邻的两行
                dp[i][j]+=dp[i-1][k];           //满足上述三个条件后,dp[i][j]加上dp[i-1][k]
            }
        }
    }//第二行之后的处理
    int ans=0;
    for (int i=1;i<=cnt;i++) ans+=dp[m][i];  //对最后一行所有可能装状态的情况数相加,即为最后的答案
    printf("%d",ans%P);
    return 0;
}

标签:状态,cnt,sta,int,题解,Fields,USACO06NOV,dp
From: https://www.cnblogs.com/ZYStream/p/18542653

相关文章

  • [CEOI2023] A Light Inconvenience 题解
    Description今年CEOI的开幕式上有一场精彩的火炬表演。表演者们站成一排,从\(1\)开始从左往右编号。每个表演者举着一根火炬,初始只有一个举着点燃的火炬的表演者。表演分为\(Q\)幕。在第\(a\)幕开始之前,要么\(p_a>0\)个表演者从右侧加入表演,他们的火炬是熄灭的;要么最......
  • gym103102H AND = OR 题解
    非常巧妙的一个题。我们首先考虑单组询问该怎么做。首先需要注意到一个结论,即设答案为\(x\),那么对于\(\forally<x\),\(y\)都应该放在与组;同样的,对于\(\forally>x\),\(y\)都应该放在与组。进一步的,我们观察在\(\text{popcount}\)上也有同样的性质,即对于\(\forally,......
  • 好题记录 [集训队互测 2023] 优惠购物 题解
    首先发现这个过程的限制比较多,那么考虑重新描述这个过程。令\(x_i\)表示在第\(i\)个物品上使用了\(x_i\)张券,那么一组\(x_{1\simn}\)就描述了一个方案。方便起见,令\(s_i\)为前i个物品买完后剩了几张券,那么有:\(s_0=m\)\(s_i=s_{i-1}+\lfloor\frac{a_i-......
  • 【题解】洛谷P7287: 「EZEC-5」魔法
    P7287「EZEC-5」魔法感觉好题有思维,但是我没认真读题,看到样例就我以为了,他让任意一个区间满足大于\(S\)即可不是全部。我们手搓一下样例就可以发现,对于加法我们不加白不加的话肯定全部的数都加上,乘法肯定要等到加完后才开始,这些都是贪心思路。然后就是开始搭配操作了,我遇到......
  • 题解:「2017 山东一轮集训 Day7」逆序对
    LibreOJ6077前置知识:生成函数、组合数先考虑平方怎么做。\(f_{i,j}\)表示处理了前\(i\)个值,逆序对有\(j\)个。显然可以转移到\(f_{i+1,j},f_{i+1,j+1},f_{i+1,j+2},...,f_{i+1,j+i}\)。然后发现这个东西是个很简单的递推,而且长得很生成函数,于是可以很自然的写成\[1\t......
  • 题解:[SCOI2016] 美味
    前置知识:可持久化线段树(主席树)洛谷3293[SCOI2016]美味问题有一个长度为\(n\)的序列\(a_1,a_2,...,a_n\)。每次询问给你\(b\)、\(x\),你需要求出\(\max\{a_i+x\bigoplusb\}\)。\(1\lel\ler\len\le2\times10^5,0\lea_i,b,x<10^5\)首先,有\(l,r\)应该......
  • AtCoder Beginner Contest 378 题解
    AtCoderBeginnerContest378题解比赛链接A-Pairing贪心#include<bits/stdc++.h>usingnamespacestd;usingi64=longlong;voidShowball(){vector<int>a(5);for(inti=0;i<4;i++){intx;cin>>x;a[x]++;......
  • 题解:[XIX Open Cup, Grand Prix of Korea] Dev, Please Add This!
    前置知识:2-SAT题意[XIXOpenCup,GrandPrixofKorea]Dev,PleaseAddThis!在一张网格上有以下几种物品:空地(.)墙(#)星星(*)一个球(O)现在你要玩一个游戏。你可以让球朝上下左右某一个方向移动,但是一旦移动就必须走到底,也就是说直到前面是墙或者边界才能停。另外,如果你走......
  • 【题解】洛谷P7286:「EZEC-5」人赢
    P7286「EZEC-5」人赢可以想到对于每个数要找到比他大的数中下标最大的数,我们按照数的大小排序,我们维护原序列的一个指针,对于每个数如果比指针大那么就左移指针,可以思考下为什么:指针上的数比现在这个数要小那比后面的数都小,于是我们左移指针直到大于这个数,可以发现我们也在一直......
  • 【题解】洛谷P8346:最澄澈的空与海
    【题解】洛谷P8346:最澄澈的空与海猜结论题,本身其实很简单,在纸上画个差不多就能想出来,我一开始想二分图最大匹配,但是还是太大了,不可以。当一个二分图有且仅有一种解时,必定有节点的入度为\(1\)。我们想到有多种匹配的情况,可以想到如果这是一个环的情况,一个左边的点将他右边的点......