zoukankan      html  css  js  c++  java
  • CodeForces 1006F Xor-Paths|Meet in the middle

    题目链接

    题目大意:给一个 (n imes m) 的网格图。每个点有一权值 (a_{i,j}),现在要从 ((1,1)) 走到 ((n,m)),且仅能向右或向下,求路径经过的点的权值异或和恰好为(k)的方案数。
    (1 le n,m le 20; 0 le k le 10^{18})

    题目思路:
    看上去找不到什么算法去解决本题,那么遇事不决上暴搜,复杂度约为 (2^{n+m}),显然不能通过,并且这是CF题没部分分
    但是我们还是找不到什么解法,只好考虑优化搜索(这一步在考场上尤为重要)。
    我们发现,在本题中,我们既可以从起点开始搜索,也可以从终点开始搜索。显然这是等价的。这条性质等下将用到。
    现在引入一个概念:双向搜索/折半搜索/Meet in the middle。顾名思义,其方法是分别从起点和终点开始,做一半路程的搜索,并保存下结果,最后进行合并。这个方法的原理就是上文从起点搜和从终点搜等价的性质。
    于是,搜索的时间复杂度由 (2^{n+m}) 变为 (2 imes 2^{frac{n+m}{2}}),可以接受。
    当然,合并答案也是很重要的一步。考虑如何快速得出答案:我们使用(map)来保存每个中间点的答案,从起点搜时记录,从终点搜时取出即可。由于结果数尚不算多,因此也可以接受
    上代码

    #include<bits/stdc++.h>
    using namespace std;
    map<long long,int> f[30][30];
    long long n,m,k,z[30][30],a[30][30],ans,t;
    void q_dfs(int x,int y,long long kk)
    {	
    	if (x>n||y>m) return ;
    	if (x+y==((n+m+2)>>1)) 
    	{f[x][y][kk]++;return ;}
    	q_dfs(x+1,y,kk^a[x+1][y]);
    	q_dfs(x,y+1,kk^a[x][y+1]);
    }//从起点开始搜
    void h_dfs(int x,int y,long long kk)
    {
    	if (x<1||y<1) return ;
    	if (x+y==((n+m+2)>>1))
    	{
    		if (f[x][y].find(k^(kk^a[x][y]))==f[x][y].end()) return ;
    		ans+=f[x][y][k^(kk^a[x][y])];
    		return ;
    	}
    	h_dfs(x-1,y,kk^a[x-1][y]);
    	h_dfs(x,y-1,kk^a[x][y-1]);
    }//从终点开始搜
    int main()
    {
    	scanf("%lld%lld%lld",&n,&m,&k);
    	for (int i=1;i<=n;i++)
    	  for (int j=1;j<=m;j++)
    	  {
    	    scanf("%lld",&a[i][j]);
    	    f[i][j].clear();
    	  }
    	q_dfs(1,1,a[1][1]);
    	h_dfs(n,m,a[n][m]);
    	cout<<ans<<endl;
    	return 0;
    }
    
  • 相关阅读:
    图片上传-下载-删除等图片管理的若干经验总结3-单一业务场景的完整解决方案
    图片上传-下载-删除等图片管理的若干经验总结2
    HDU 1195 Open the Lock
    HDU 1690 Bus System
    HDU 2647 Reward
    HDU 2680 Choose the best route
    HDU 1596 find the safest road
    POJ 1904 King's Quest
    CDOJ 889 Battle for Silver
    CDOJ 888 Absurdistan Roads
  • 原文地址:https://www.cnblogs.com/fmj123/p/14082531.html
Copyright © 2011-2022 走看看