• JZOJ 4250. 【五校联考7day1附加题】路径(折半搜索)


    JZOJ 4250. 【五校联考7day1附加题】路径

    题目

    Description

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

    Input

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

    Output

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

    Sample Input

    3 6
    0 1 3
    1 0 2
    3 2 0

    Sample Output

    2

    Data Constraint

    对于30%, 1 ≤ n ≤ 10 1≤n≤10 1n10.
    对于另外30%, 1 ≤ n ≤ 14 , 1 ≤ l ≤ 30 1≤n≤14,1≤l≤30 1n141l30.
    对于100%, 1 ≤ n ≤ 14 , 1 ≤ A i , j ≤ 1 0 8 , 1 ≤ l ≤ 2 ∗ 1 0 9 1≤n≤14,1≤A_{i,j}≤10^8,1≤l≤2*10^9 1n141Ai,j1081l2109.
    悄悄告诉你:数据的答案都很大,反正直接输 0 0 0是没分的,但都在int范围内。
    为了降低题目难度, A i , j A_{i,j} Ai,j的种类数不会太多

    题解

    • 看到数据限制的最后一行我什么都不想说。。。

    • 这句话能说明什么我现在都不清楚。。。

    • 进入正题,

    • 第一档的部分分可以暴力DFS解决,

    • 第二档的部分分可以状压DP解决,

    • 第三档呢?

    • 也能像第二档一样状压DP吗?

    • 乍一看好像是可以的,怎么记录路径长度和呢?

    • GG了,此方法不可做——

    • DFS吗?直接这么做似乎最大时间复杂度 O ( n ! ) = 14 ! = 87178291200 ≈ 8.7 ∗ 1 0 10 O(n!)=14!=87178291200≈8.7*10^{10} O(n!)=14!=871782912008.71010,显然超时,

    • 有一种神奇的搜索叫做折半搜索!!!

    • 顾名思义,把要搜索的东西给折半

    • 主要过程如下:

    • 前一半,DFS找出从 1 1 1出发经过的一半的点得到的状态,记录下它和对应的方案数。

    • 状态包括到达的点 k k k,经过了点的状态 s s s(状态压缩,不包括 1 1 1),路径长度和 s u m sum sum.

    • 这些用哈希表存下来,对于相同的 k , s , s u m k,s,sum k,s,sum,不需重复记录,只要给对应的方案数 + 1 +1 +1.

    • 后一半,同样使用DFS找出从 1 1 1出发经过一半的点得到的状态,不需记录,

    • 状态包括到达的点 k k k,经过了点的状态 s s s(状态压缩,不包括 1 1 1),路径长度和 s u m sum sum.

    • 此时,到哈希表里找到和这个状态对应的(能组成一条完整的路线的)状态,

    • 直接查找 ( k , s , s u m ) (k,s,sum) (k,s,sum)

    • 当然不是!(难道两条完全相同的路径能组成一条符合题目条件的回路吗?)

    • 第一维,查找的是 k k k,对应走到的当然要是相同的点。

    • 第二维,查找的是 2 n − 1 − s − 1 + 2 k − 1 2^n-1-s-1+2^{k-1} 2n1s1+2k1 2 n − 1 2^n-1 2n1是包括每个点的压缩后的状态, − s -s s是减去了当前经过的点压缩后的状态, − 1 -1 1是减去点 1 1 1的状态, + 2 k − 1 +2^{k-1} +2k1是加回当前点的状态。

    • 第三维,查找的是 l − s u m l-sum lsum,因为两半的路径和要等于 l l l

    • 所以后一半到哈希表里查找 ( k , 2 n − 1 − s − 1 + 2 k − 1 , l − s u m ) (k,2^n-1-s-1+2^{k-1},l-sum) (k,2n1s1+2k1,lsum),找到则加上对应的方案数

    代码

    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define md 9999997
    #define LL long long
    int n,len;
    int dis[15][15],e[15],bz[15];
    LL ans=0;
    struct
    {
    	int k,s,sum;
    	LL tot;
    }hs[20000010];
    void hash(LL k,LL s,LL sum)
    {
    	LL x=k*s%md*sum%md;
    	int ok=0;
    	while(hs[x].k)
    	{
    		if(hs[x].k==k&&hs[x].s==s&&hs[x].sum==sum) 
    		{
    			hs[x].tot++;
    			ok=1;
    			break;
    		}
    		x++;
    		if(x>20000000) x=0;
    	}
    	if(!ok) hs[x].k=k,hs[x].s=s,hs[x].sum=sum,hs[x].tot=1;
    }
    void find(LL k,LL s,LL sum)
    {
    	LL x=k*s%md*sum%md;
    	while(hs[x].k)
    	{
    		if(hs[x].k==k&&hs[x].s==s&&hs[x].sum==sum)
    		{
    			ans+=hs[x].tot;
    			break;
    		}
    		x++;
    		if(x>20000000) x=0;
    	}
    }
    int ss=0;
    void dfs(int k,int x,int s,int sum,int z)
    {
    	if(x>z) hash(k,s,sum),ss++;
    	else
    	{
    		for(int i=2;i<=n;i++) if(!bz[i])
    		{
    			bz[i]=1;
    			if(sum+dis[k][i]<=len) dfs(i,x+1,s+e[i-1],sum+dis[k][i],z);
    			bz[i]=0;
    		}
    	}	
    }
    void dfs1(int k,int x,int s,int sum,int z)
    {
    	if(x>z) find(k,e[n]-s-2+e[k-1],len-sum);
    	else
    	{
    		for(int i=2;i<=n;i++) if(!bz[i])
    		{
    			bz[i]=1;
    			if(sum+dis[k][i]<=len) dfs1(i,x+1,s+e[i-1],sum+dis[k][i],z);
    			bz[i]=0;
    		}
    	}	
    }
    int main()
    {
    	int i,j;
    	scanf("%d%d",&n,&len);
    	for(i=1;i<=n;i++)
    		for(j=1;j<=n;j++) scanf("%d",&dis[i][j]);
    	e[0]=1;
    	for(i=1;i<=14;i++) e[i]=e[i-1]*2;
    	if(n%2==0) 
    	{
    		dfs(1,1,0,0,n/2);
    		dfs1(1,1,0,0,n/2);
    	}
    	else
    	{
    		dfs(1,1,0,0,n/2);
    		dfs1(1,1,0,0,n/2+1);
    	}
    	printf("%lld",ans);
    	return 0;
    }
    
    哈哈哈哈哈哈哈哈哈哈
  • 相关阅读:
    kali渗透综合靶机(十七)--HackInOS靶机
    kali渗透综合靶机(十六)--evilscience靶机
    kali渗透综合靶机(十五)--Breach-1.0靶机
    kali渗透综合靶机(十四)--g0rmint靶机
    DVWA-文件上传学习笔记
    kali渗透综合靶机(十三)--Dina 1.0靶机
    Weblogic-SSRF漏洞复现
    kali渗透综合靶机(十二)--SickOs1.2靶机
    IIS_CVE-2015-1635-HTTP.SYS远程执行代码漏洞复现
    【Flask+Redis】 python学习第一章
  • 原文地址:https://www.cnblogs.com/LZA119/p/13910089.html
Copyright © 2020-2023  润新知