A Simple Task CodeForces - 11D【状压dp】
参考博客:
CodeForces - 11D A Simple Task
好久没写状压dp了,对于集合状态的表示都有些生疏:
空集.............................0
只含有第i个元素的集合{i}............1<<i
含有全部n个元素的集合{0,1...n-1}....(1<<n)-1//含有n个元素的全集
判断第i个元素是否属于集合S...........if(S>>i&1)
向集合中加入第i个元素S∪{i}..........s|1<<i
从集合中取出第i个元素...............s&~(1<<i)
集合S和T的并集S∪T.................S|T
集合S和T的交集S∩T.................S&T
推荐配合一起食用:集合的二进制数表示
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define MAXN 20
#define INF 0x3f3f3f3f
#define LL long long
int n,m;
LL dp[1<<MAXN][MAXN];//路径条数会爆int
int g[MAXN][MAXN];//数据范围很小,用邻接矩阵可以方便地判断2点是否联通
int st(int s)//求点集中最右边的1,即节点编号最小的点
{
int ret=1;
while(s)
{
if(s%2)
return ret;
s>>=1,ret++;
}
}
int main()
{
int u,v;
LL ans=0;
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d %d",&u,&v);
g[u][v]=g[v][u]=1;
}
int S=(1<<n)-1;//含有n个元素的全集
for(int i=1;i<=n;i++)
dp[(1<<(i-1))][i]=1;//每个点到自己的路径条数为1
for(int s=1;s<=S;s++)
for(int u=1;u<=n;u++)
{
if(dp[s][u]==0) continue;
int fir=st(s);//求起点
for(int v=fir;v<=n;v++)
if(u!=v&&g[u][v])
{
if((s&(1<<(v-1)))&&v==fir)
ans+=dp[s][u];
else if( !(s&(1<<(v-1))))
{
int ss=s|(1<<(v-1));
dp[ss][v]+=dp[s][u];
}
}
}
ans-=m;//减去互相连边的情况 1->2->1
ans/=2;//每种都会算两次 1->2->4->3->1=1->3->4->2->1
printf("%lld\n",ans);
}
转载请注明出处,有疑问欢迎探讨
博主邮箱 2775182058@qq.com
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现