【题解】CF11D A Simple Task(状压 DP)
【题解】CF11D A Simple Task
题目链接
题意概述
给定一张
思路分析
看到数据范围,考虑对点数状压。
一个比较常见的套路是将一个环拆成两个点之间的路径,即对于环上两点
那么我们就可以把环转化成路径,即用
那么最后的答案就为对于每个
考虑空间:250mb
,显然会爆掉。考虑优化空间。
状压中比较常见的一种优化办法就是用
我们每次考虑只让一个状态中最小的点,即
那么我们可以定义
考虑转移。
首先枚举集合
那么
-
当
在集合 内时:- 当
时,这是一个特殊情况。也就是说从 构成了一个回路(环),所以将此时的 累加入答案即可。 - 当
时,由于我们的 是枚举的下一个要加入集合的点。所以这里不做处理。
- 当
-
当
不在集合 内时:将
加入集合,那么有:
还有一个易错点:
对于每一个算出来的答案,我们会将无向图产生的重边计算成二元环,所以答案要减去
障碍点
-
没有考虑到空间产生的问题,从而没有想到利用
来优化。因此以后每道题目还是想到一个思路后先计算一下空间,防止
MLE
。
易错点:
- 答案应为
而非 ,原因在上面思路分析中已经说明过。
一些技巧
此题包含两个重要技巧:
- 对于环的问题应该想到将其拆分成环上两点
和 的两条路径; - 对于状压要考虑到
优化。
代码实现
//CF11D
#include<cstdio>
#include<iostream>
#define int long long
using namespace std;
const int maxn=20;
int dp[1<<maxn][maxn],a[maxn][maxn];
int ans=0;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int lowbit(int x){return x&(-x);}
signed main()
{
int n=read(),m=read();
for(int i=1;i<=m;i++)
{
int u,v;
u=read();v=read();
u--;v--;
a[u][v]=a[v][u]=1;
}
for(int i=0;i<n;i++)dp[1<<i][i]=1;
for(int sta=1;sta<(1<<n);sta++)
{
for(int i=0;i<n;i++)
{
if(!dp[sta][i])continue;
if(!(sta&(1<<i)))continue;
for(int j=0;j<n;j++)
{
if(!a[i][j])continue;
if(lowbit(sta)>(1<<j))continue;
if(lowbit(sta)==(1<<j))ans+=dp[sta][i];
else if(!(sta&(1<<j)))dp[sta|(1<<j)][j]+=dp[sta][i];
}
}
}
cout<<((ans-m)>>1)<<'\n';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!