[折半搜索][has] Jzoj P4250 路径
题解
- 题目大意:有n个城市,问每个城市都走一遍,路径长度刚好为L的方案数
- 30%,暴力乱搜就好了,O(n!)
- 60%,n<=14,状压dp,设f[i][j][k]表示当前经过的点的状态为i,现在在点j,当前路径长为k,O(2^n*n^2*30),听说加个map可以跑70分
- 100%,n<=14,折半搜索可以过
- 记前半段除了1与i长度为n1,后半段为n2,那么如果确定了i,只要满足前半段与后半段经过的点不重复且路径总长为l就可以计算答案了
- 具体来说就是就是枚举一个点i,枚举前半段的所有情况,用hash记下来,再枚举后半段的所有情况
- 并在hash中找到与之对应的前半段,统计进答案中就好了
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #define mo 19260817 5 #define ll long long 6 #define N 15 7 using namespace std; 8 int n,m,l,a[N][N],f[mo],ans,i; 9 ll g[mo]; 10 ll calc(int x,int y,int k){ return x*32768000000000ll+y*2000000000ll+k; } 11 int gethash(int x,int y,int k) 12 { 13 ll r=calc(x,y,k); 14 for (i=r%mo;g[i]&&g[i]!=r;++i==mo?i=0:i); 15 return i; 16 } 17 void dfs1(int d,int x,int y,int k) 18 { 19 if (x&&k>=l) return; 20 if (d>=m) 21 { 22 int p=gethash(x,y,k); 23 g[p]=calc(x,y,k),f[p]++; return; 24 } 25 for (int i=1;i<n;i++) if (!(y>>i&1)) dfs1(d+1,i,y|1<<i,k+a[x][i]); 26 } 27 void dfs2(int d,int x,int y,int k) 28 { 29 if (x&&k>=l) return; 30 if (d>=m) 31 { 32 int p=gethash(x,((~y)&((1<<n)-1))|1|1<<x,l-k); 33 ans+=f[p]; return; 34 } 35 for (int i=1;i<n;i++) if (!(y>>i&1)) dfs2(d+1,i,y|1<<i,k+a[x][i]); 36 } 37 int main() 38 { 39 scanf("%d%d",&n,&l); 40 for (int i=0;i<n;i++) for (int j=0;j<n;j++) scanf("%d",&a[i][j]); 41 m=n/2,dfs1(0,0,1,0),m=n-m,dfs2(0,0,1,0),printf("%d",ans); 42 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步