题解

我们从最简单的思路开始考虑,首先看到题目发现\(n\)非常小,于是很容易想到状态压缩。

我们考虑比较直觉的状态,f[i][j][k]表示以i为起点,当前在j,之前去过的点状态为k的简单环的方案数。

仔细思考以后,我们发现这个状态有问题,问题在于,每一个环再环内的每个点都被计算了一次。

那么怎么避免这种状态呢?我们考虑让每个环仅由其中编号最小的点贡献。

这样操作了以后,每个环仍然被计算了两遍(顺时针一次,逆时针一次),但是关系不大,最后统计答案的时候除2即可。

考虑到起点已经是环中最小的点了,于是我们无需再状态里额外记录它。

于是将状态变换成f[i][j]表示当前在i,之前去过的点状态为j的简单环的方案数。

那么状态之间如何转移呢?直接DP有些困难,于是我们使用记忆化搜索。

在记忆化搜索的时候要记录一个值表示当前去过几个点,因为显然数量在2即以下的点构不成简单环,但会被记搜记录答案,特判即可。

代码

#include <cstdio>

namespace fast_IO{
const int IN_LEN = 10000000, OUT_LEN = 10000000;
char ibuf[IN_LEN], obuf[OUT_LEN], *ih = ibuf + IN_LEN, *oh = obuf, *lastin = ibuf + IN_LEN, *lastout = obuf + OUT_LEN - 1;
inline char getchar_(){return (ih == lastin) && (lastin = (ih = ibuf) + fread(ibuf, 1, IN_LEN, stdin), ih == lastin) ? EOF : *ih++;}
inline void putchar_(const char x){if(oh == lastout) fwrite(obuf, 1, oh - obuf, stdout), oh = obuf; *oh ++= x;}
inline void flush(){fwrite(obuf, 1, oh - obuf, stdout);}
int read(){
int x = 0; int zf = 1; char ch = ' ';
while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar_();
if (ch == '-') zf = -1, ch = getchar_();
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar_(); return x * zf;
}
void write(long long x){
if (x < 0) putchar_('-'), x = -x;
if (x > 9) write(x / 10);
putchar_(x % 10 + '0');
}
} using namespace fast_IO; struct Edge{
int to, next;
} edges[1005]; int head[20], edge_num = 0; inline void addEdge(int from, int to){
edges[++edge_num] = (Edge){to, head[from]};
head[from] = edge_num;
} long long f[20][1048577];
int vis[20]; long long DFS(int frt, int u, int sta, int cnt){
vis[u] = 1;
if (f[u][sta])
return f[u][sta];
for (int c_e = head[u]; c_e; c_e = edges[c_e].next){
int v = edges[c_e].to;
if ((1 << (v - 1)) & sta){
if (cnt > 2 && v == frt)
++f[u][sta];
}
else
if (v > frt)
f[u][sta] += DFS(frt, v, sta | (1 << (v - 1)), cnt + 1);
}
return f[u][sta];
} int main(){
int n = read(), m = read();
for (int i = 0; i < m; ++i){
int u = read(), v = read();
addEdge(u, v), addEdge(v, u);
}
long long ans = 0;
for (int i = 1; i <= n; ++i)
ans += DFS(i, i, (1 << (i - 1)), 1);
write(ans / 2); flush();
return 0;
}

最新文章

  1. mybaits 框架运用
  2. [Android]RapidFloatingActionButton框架正式出炉
  3. 初学svn对版本进行控制 用post- commit钩子实现代码同步到web目录
  4. Centos安装firefox/chrome
  5. 洛谷P1121 环状最大两段子段和
  6. 剑指Offer44 扑克牌的顺子
  7. Appium Python Driver Api
  8. 201521123105 第11周Java学习总结
  9. 【译】The Accidental DBA:SQL Server Backup
  10. hdu 5700区间交(线段树)
  11. ASP.NET Core在CentOS上的最小化部署实践
  12. 阿里云服务器部署Java Web项目全过程
  13. 文本编辑利器Notepad++ 10个强大而又鲜为人知的特性【转】
  14. Linux中的wheel用户组是什么?
  15. 魔术方法:__set、__get
  16. spring boot集成redis的血泪史
  17. MFC连接MySQL数据库方法
  18. 为什么行内元素不能设置margin-top/margin-bottom/padding-top/padding-bottom?
  19. Mybatis的类型处理器
  20. proe工程图输出dwg/dxf文件设置

热门文章

  1. vue --- vscode 配置 .vue文件生成结构
  2. Angular5 父组件获取子组件实例( ViewChildren、ViewChild用法)
  3. mysql主要性能监控指标
  4. Oracle 查看 impdp 正在执行的内容
  5. spring配置添加多个事务(转)
  6. fatal: refusing to merge unrelated histories问题解决
  7. gym102215题解
  8. google浏览器切换成中文
  9. 23、selenium爬取歌曲精彩评论
  10. node.js使用express模块创建web服务器应用