zoukankan      html  css  js  c++  java
  • [折半搜索][has] Jzoj P4250 路径

    Description

    A国有n个城市,编号为1到n,任意两个城市之间有一条路。shlw闲得没事干想周游A国,及从城市1出发,经过且仅经过除城市1外的每个城市1次(城市1两次),最后回到城市1。由于shlw很傻,他只愿意走一定长度,多了少了都不干,现在他想知道一共有多少种方案可供选择。
     

    Input

    第一行为两个整数n,l,分别为城市数和路程总长。
    之后n行,每行n个整数,其中第i行第j列为Ai,j,满足Ai,i=0;Ai,j=Aj,i。

    Output

    输出共1行,为总方案数。
     

    Sample Input

    3 6
    0 1 3
    1 0 2 
    3 2 0

    Sample Output

    2
     

    Data Constraint

    对于30%,1<=n<=10
    对于另外30%,1<=n<=14,1<=l<=30
    对于100%,1<=n<=14,1<=Ai,j<=100,000,000,1<=l<=2,000,000,000
    悄悄告诉你:数据的答案都很大,反正直接输0是没分的,但都在int范围内。
    为了降低题目难度,Ai,j的种类数不会太多

    题解

    • 题目大意:有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,折半搜索可以过
    • 记前半段除了1i长度为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 }
  • 相关阅读:
    jsp mysql 配置线程池
    服务端 模拟 检测 攻击。。乱写
    硕思闪客精灵 7.2 破解版
    unity UnityAwe 插件
    smartfoxserver 2x 解决 Math NAN
    unity 断点下载
    java 监听文件目录修改
    wind7 64 setup appjs
    sfs2x 修改jvm 内存
    unity ngui 解决图层问题
  • 原文地址:https://www.cnblogs.com/Comfortable/p/10339544.html
Copyright © 2011-2022 走看看