首页 > 其他分享 >状压DP

状压DP

时间:2024-05-31 23:46:22浏览次数:19  
标签:状态 int 状压 dp dfs DP 一行 国王

状压DP

[SCOI2005] 互不侵犯

点击查看题面

题目描述

在 \(N \times N\) 的棋盘里面放 \(K\) 个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共 \(8\) 个格子。

输入格式

只有一行,包含两个数 \(N,K\)。

输出格式

所得的方案数

样例 #1

样例输入 #1

3 2

样例输出 #1

16

提示

数据范围及约定

对于全部数据,\(1 \le N \le 9\),\(0 \le K \le N\times N\)。


\(\text{upd 2018.4.25}\):数据有加强。

首先看到这一题就应该想到用$dfs$来解决,毕竟$n$也才$9$。$dfs$的思路就是看当前点是否要放国王,如果要放国王的话,就得判断当前点是否可以放国王。这个思路的时间复杂度分析是:首先,每一个决策都有两个分支也就是$O(2^?)$,那么这个$?$就是决策的状态数,也就是整个棋盘也就是$n^2$,也就是$k$,那么整体复杂度就是$O(2^k)$。这个时间复杂度已经超过了$1$秒,所以说要进行优化。

优化

可以发现,这道题超时的原因是枚举的没用状态太多了,所以说只要我们去掉这些状态那么时间复杂度就是最优的了。

首先可以想到的就是\(dp\),\(dp\)的本质就是优化\(dfs\)。可以发现当前这一行的状态是需要用放到\(dp\)状态里,又不可能把添加\(n\)维表示当前点是否放了国王。可以发现如果把这\(n\)维合并成\(1\)维,这个合共其实可以把一个二进制当成当前的状态比如说\(10010_2\)表示从左到右第\(1\)位有一个国王,第\(4\)位也有一个国王。这个技巧就被称为状态压缩,状态压缩之后的操作可以使用位运算来解决。下图是一张关于位运算的表格:

<< 二进制左移
>> 二进制右移
& 两个二进制每一位只要是\(0\)那么结果中这一位就是\(0\)
^ 相同为\(0\),不同为\(1\)
| 两个二进制每一位只要是\(0\)那么结果中这一位就是\(0\)

回到这一题那么我们的状态就可以设成\(f_{i,j,k}\)表示在第\(i\)行中,状态为\(j\),放置了\(k\)个国王的方案数

好,我们现在就要写出这一题的转移方程,因为国王的攻击范围涉及到上一行所以我们需要找到上一行,因此我们就要把上一行的状态也放进当前状态里。所以状态方程就应该是:

\[dp_{i,j,l}+=dp_{i-1,x,l-num_j}; \]

\(i\)是行数,\(j\)是这一行的状态,\(x\)是上一行的状态,\(l\)是这一行和上一行选择的国王数,\(num_i\)表示第i个状态的国王数。
那么该怎么求道第\(i\)行的国王数和状态的??
其实这个问题是对于一行上的,那么就可以用\(dfs\)来枚举每一个状态即可。
实现过程:

void dfs(int x, int sum, int cur) {
    if (cur >= n) {
		sta[++cnt] = x;
		num[cnt]=sum;
		return;
	}
    dfs(x,sum,cur+1);
	dfs(x+(1<<cur),sum+1,cur+2);
}

那么最终的答案就应该是对于最后一行一种状态放置所有国王的方案综合也就是:

\[\sum_{i是状态}{dp_{n,i,k}} \]

最终代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=10; 
int sta[1<<N],num[1<<N],cnt,n,k,ans;
int dp[N][1<<N][N*N];
void dfs(int x, int sum, int cur) {
    if (cur >= n) {sta[++cnt] = x,num[cnt]=sum;return;}
    dfs(x,sum,cur+1),dfs(x+(1<<cur),sum+1,cur+2);
}
bool check(int i,int j){return !(sta[i]&sta[j]||(sta[i]<<1)&sta[j]||sta[i]&(sta[j]<<1));}
signed main(){
	cin>>n>>k;
	dfs(0,0,0);	
	for(int i=1;i<=cnt;i++)dp[1][i][num[i]]=1;
	for(int i=2;i<=n;i++)
		for(int j=1;j<=cnt;j++)
			for(int x=1;x<=cnt;x++){
				if(!check(j,x))continue;
				for(int l=num[j];l<=k;l++)dp[i][j][l]+=dp[i-1][x][l-num[j]];
			}
	for(int i=1;i<=cnt;i++)ans+=dp[n][i][k];
	return cout<<ans,0;
}

标签:状态,int,状压,dp,dfs,DP,一行,国王
From: https://www.cnblogs.com/williamYcY/p/18225441

相关文章

  • DP笔记
    DP笔记目录DP笔记一、动态规划总结二、线性DP三、背包问题四、区间DP五、树形DP换根DP(也算是树形的DP)六、状压DP七、数位DP八、概率DP、期望DP一、动态规划总结要使用动态规划需要哪些条件?最优子结构子问题重叠无后效性1和2中只需要满足一个,再加上3,接下来就可以愉快......
  • udp的收发包的思考
      在测试radius性能时,想到一个问题,以前tcp报文在ip层处理时,涉及到路由查找,对于tcp协议报文;skb中没有路由缓存,没有关联的sock;且非分片报文;ip_early_demux设置为true;则调用early_demux函数提前在IP层做established状态的sock查找,并负责将sock结构体成员sk_rx_dst的路由缓存赋值......
  • python 把指定的一张图片 改为 jpg dpi 300
    使用了Python的Pillow库fromPILimportImageImage.MAX_IMAGE_PIXELS=2000000000#设置最大处理像素极限defconvert_image_to_jpg(input_path,output_path,dpi=300):withImage.open(input_path)asimg:#设置DPIimg.info['dpi']=(dpi,dp......
  • UE4中PhysX BroadPhase(碰撞检测的粗略阶段)
    PhysX的BroadPhase(碰撞检测的粗略阶段),具体是用AABB(轴向包围盒)来做碰撞检测具体算法有两种:SAP(SinglePruningBox,单个剪枝盒)和MBP(MultiPruningBox,多个剪枝盒) SAP(Single PruningBox,单个剪枝盒)当场景中有大量的物体(大世界有百万级别)时,即使它们已按AABB的三个轴向xyz做了排序......
  • 《计算机网络微课堂》5-3 UDP和TCP的对比
    本节课我们将从几个方面对比UDP和TCP。UDP和TCP是TCP/IP体系结构运输层中的两个重要协议,如图所示,这是我们之前课程中介绍过的TCP/IP体系结构,它的运输层有两个非常重要的协议UDP和TCP。在使用TCP/IP体系结构的网络通信中,这两个协议的使用频率仅次于往基层的IP协......
  • UDP网络聊天室(更)
    服务器端#include<header.h>typedefstructnode{ charname[20]; structsockaddr_incli_addr; structnode*next;}node,*node_p;typedefstructmsg{ chartype; charname[20]; chartext[128];}msg;node_pcreate_link(){ node_pH=(node_p)malloc(s......
  • TCP和UDP协议的特点和用途
    TCP(TransmissionControlProtocol):特点:面向连接、可靠传输、按序交付、流量控制、拥塞控制。用途:适用于需要高可靠性的数据传输,如网页浏览、电子邮件、文件传输等。优势:数据包顺序和完整性有保障,适合需要准确无误传输数据的场景。举例:在线购物网站的交易数据传输,确保每笔交易......
  • 根据不同的dpi 媒体查询
    /*默认样式*/.element{width:100px;height:100px;background-color:blue;}/*当设备像素比为1.5时,调整.element的宽度*/@mediascreenand(resolution:144dpi){.element{width:150px;}}/*当设备像素比为1.0时,调整.element的宽度*/@mediascreenand(r......
  • [SDCPC2023] Colorful Segments 线段树转移DP
    Codeforces链接​  洛谷题目链接#[SDCPC2023]ColorfulSegments##题面翻译**【题目描述】**考虑数轴上的$n$条线段,其中第$i$条线段的左端点为$l_i$,右端点为$r_i$。每一条线段都被涂上了颜色,其中第$i$条线段的颜色为$c_i$($0\lec_i\le1$)。颜色共有两种,$c_i......
  • 第一道DP黄
    最近发生了很多事,最近一个月一直在刷DP,但是成效甚微,常常是在“读题”->“不会”->“看题解”->“了解状态表示和转移方程”->“照葫芦画瓢写个代码交上”中循环,感觉真的蛮绝望的,就像一直在挣扎着往前,却总发现自己还在原地。之后就是省赛爆炸,今天又训了一天dp,对着四维棋盘......