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
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:使用Catalyst进行自然语言处理
· 分享一个我遇到过的“量子力学”级别的BUG。
· Linux系列:如何调试 malloc 的底层源码
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 历时 8 年,我冲上开源榜前 8 了!
· 物流快递公司核心技术能力-海量大数据处理技术
· 四大AI编程工具组合测评
· 关于能否用DeepSeek做危险的事情,DeepSeek本身给出了答案
· 如何在 Github 上获得 1000 star?