P1433 吃奶酪 标签: 动态规划,dp | 状态压缩
详见:https://www.luogu.com.cn/problem/P1433
-
有可以简便记录存储勾股定理的方式,但是我要简便,就是直接传结构体的点,就用不了这个,或许可以用哈希,但是会搞得更麻烦
- 其实感觉更多的因素是懒~~~
就不写基础原理了,直接看注释吧
点击打开非map版
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> using namespace std; int all, n; double ans = 200000000; struct point { double x, y; } a[100]; double dp[1 << 15][20] = {}; int lowbit(int x) { return x & (-x); } // 快速log2 很巧妙的思路 int log2_fast(int n) { int result = 0; if(n&0xffff0000) { result += 16; n >>= 16; } if(n&0x0000ff00) { result += 8; n >>= 8; } if(n&0x000000f0) { result += 4; n >>= 4; } if(n&0x0000000c) { result += 2; n >>= 2; } if(n&0x00000002) { result += 1; n >>= 1; } return result; } double gougu(point x, point y) { double xc, yc; xc = abs(x.x - y.x); yc = abs(x.y - y.y); return sqrt(xc*xc+yc*yc); } // 用引用节省内存,假设递归次数较多这个是重要的!!! void dfs(double di, int state, point& be) { // 剪枝优化, 根据已走的路程判断当前分支是否可以做得更好 if(di >= ans) { return; } // 深搜结束 if(state == all) { // 选择最优 ans = min(di, ans); return; } // 解析状压,转换为二进制其实使用 int vis = all - state; 效果也是一摸一样的 int vis = all&(~state); for(int i=vis; i; i -= lowbit(i)) { int x = lowbit(i); // 转换为数组下标 int j = log2_fast(x); // 求出给下一个深搜的参数 int nextState = state+x; double nextdi = di+gougu(be, a[j]); // 剪枝,很简单的道理,这条路走了,就不走了 // 记录成double的原因是就算当前坐在的节点和状态相同,走的距离也可以不相同,所以需要更多的信息作比较 if(dp[nextState][j]!=0 && dp[nextState][j]<=nextdi) { continue; } // 记录 dp[nextState][j] = nextdi; // 接着深搜 dfs(nextdi, nextState, a[j]); } } int main() { // 初始化 cin >> n; all = (1<<n)-1; for(int i = 0; i<n; i++) { cin >> a[i].x >> a[i].y; } point t; t.x = t.y = 0; // 深搜的参数有三个,分别为距离,状压后的是否使用和当前点 dfs(0, 0, t); printf("%.2f", ans); return 0; }
/** * 本程序使用了map来,记忆化勾股定理的数,map很慢,会超时,实测不使用map来存储也可以过 * 非要用map的话就吸氧罢(O2),吸氧后的和不吸氧的普通的差不多耗时 **/ #include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <map> using namespace std; int all, n; double ans = 200000000; struct point { double x, y; } a[100]; map<pair<double, double>, double> dis; double dp[1 << 15][20] = {}; int lowbit(int x) { return x & (-x); } // 快速log2 很巧妙的思路 int log2_fast(int n) { int result = 0; if(n&0xffff0000) { result += 16; n >>= 16; } if(n&0x0000ff00) { result += 8; n >>= 8; } if(n&0x000000f0) { result += 4; n >>= 4; } if(n&0x0000000c) { result += 2; n >>= 2; } if(n&0x00000002) { result += 1; n >>= 1; } return result; } double gougu(point x, point y) { // 算差,利用差来记忆数据 double xc, yc; xc = abs(x.x - y.x); yc = abs(x.y - y.y); if(xc > yc) { swap(xc, yc); } pair<double, double> t(xc, yc); if(dis[t] != 0) { return dis[t]; } return dis[t] = sqrt(xc*xc+yc*yc); } // 用引用节省内存,假设递归次数较多这个是重要的!!! void dfs(double di, int state, point& be) { // 剪枝优化, 根据已走的路程判断当前分支是否可以做得更好 if(di >= ans) { return; } // 深搜结束 if(state == all) { // 选择最优 ans = min(di, ans); return; } // 解析状压,转换为二进制其实使用 int vis = all - state; 效果也是一摸一样的 int vis = all&(~state); for(int i=vis; i; i -= lowbit(i)) { int x = lowbit(i); // 转换为数组下标 int j = log2_fast(x); // 求出给下一个深搜的参数 int nextState = state+x; double nextdi = di+gougu(be, a[j]); // 剪枝,很简单的道理,这条路走了,就不走了 // 记录成double的原因是就算当前坐在的节点和状态相同,走的距离也可以不相同,所以需要更多的信息作比较 if(dp[nextState][j]!=0 && dp[nextState][j]<=nextdi) { continue; } // 记录 dp[nextState][j] = nextdi; // 接着深搜 dfs(nextdi, nextState, a[j]); } } int main() { // 初始化 dis.clear(); cin >> n; all = (1<<n)-1; for(int i = 0; i<n; i++) { cin >> a[i].x >> a[i].y; } point t; t.x = t.y = 0; // 深搜的参数有三个,分别为距离,状压后的是否使用和当前点 dfs(0, 0, t); printf("%.2f", ans); return 0; }
写这篇题解的时候运气太背啦!!!
先是luogu爆网关,然后博客园爆网关
感觉最近互联网不太平啊
本文来自博客园,作者:月神的使者,转载请注明原文链接:https://www.cnblogs.com/dffxd/p/17204836.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现