【Codeforces1006F】Xor-Paths
题目链接:http://codeforces.com/contest/1006/problem/F
%%%dalao
dalao们都说这是道模板题,呵呵,确实,但双向广搜(此题深搜也可以)写过的人比较少。
这道题可以考虑直接暴力,显然并不能A掉,因为每次向右下扩展一层,状态数增长不超过2倍,复杂度是O(2^(m+n))的。
而如果采用双向广搜,从左上结点向下扩展至中心线,再从右下结点向上扩展至中心线,结果的重叠部分就是答案。
上述做法有个好玩的名字——meet in the middle。
关于实现细节,注意以下几点:
1、部分数据用long long,long long可以到2^63-1,int可以到2^31-1,因为有些数据是可以达到10^18的,所以要使用long long,包括ans。
2、我们定义状态为结点的坐标及已得到(或得到)的异或和。
3、取中心线时,要注意适当移动一下,使得其更靠近中心。
4、第一次和第二次广搜是略有区别的。。。包括状态的扩展。
5、扩展状态时注意加条件,因为n,m不一定相等,所以要避免扩展的状态出界。
1 #include<cstdio> 2 #include<iostream> 3 #include<map> 4 #include<queue> 5 using namespace std; 6 typedef long long ll; 7 const int mmax=25; 8 int n,m; 9 ll k,mt[mmax][mmax],ans; 10 struct node { 11 int x,y; 12 ll num; 13 node(int x,int y,ll num):x(x),y(y),num(num) {} 14 }; 15 queue<node> q; 16 map<ll,int> M[mmax]; 17 int main() { 18 ios::sync_with_stdio(false); 19 cin.tie();cout.tie(); 20 cin>>n>>m>>k; 21 for(int i=1;i<=n;++i) 22 for(int j=1;j<=m;++j) cin>>mt[i][j]; 23 int mid=(n+m+2)/2; 24 q.push(node(1,1,mt[1][1])); 25 while(!q.empty()) { 26 int x=q.front().x,y=q.front().y; 27 ll num=q.front().num; 28 q.pop(); 29 if(x+y==mid) { 30 if(!M[x].count(num)) M[x].insert(pair<ll,int>(num,1)); 31 else ++M[x][num]; 32 } 33 else { 34 if(y<m) q.push(node(x,y+1,num^mt[x][y+1])); 35 if(x<n) q.push(node(x+1,y,num^mt[x+1][y])); 36 } 37 } 38 q.push(node(n,m,k)); 39 while(!q.empty()) { 40 int x=q.front().x,y=q.front().y; 41 ll num=q.front().num; 42 q.pop(); 43 if(x+y==mid) ans+=M[x][num]; 44 else { 45 if(y>1) q.push(node(x,y-1,num^mt[x][y])); 46 if(x>1) q.push(node(x-1,y,num^mt[x][y])); 47 } 48 } 49 cout<<ans; 50 return 0; 51 }