双向搜索
双向搜索(meet in the middle),用于处理数据量小但是还没达到暴搜要求,比如 \(O(2^{40})\) ,使用双向搜索可以优化到 \(O(2^{20})\) 。
算法如其名,从两端同时搜索最后在中间相遇,每端搜索只需要处理一半数据量。
题目1 很难评,写了一个假的双向搜索然后 \(tle\) 给 \(t\) 疯了。。
简单分析对于 \(n\leq 20\) 一共需要 \(2*n-2\) 步走到终点,每一步都有两个选择,所以暴搜一共 \(2^{(2*n-2)}\) 中情况,显然是不可行的,但是 \(2^{(n-1)}\) 就ok。所以考虑双向搜索(注意走到斜对角线时 \(return\) ,因为没写导致 \(t\) 麻了,自以为没错误实则是假双搜)。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define inf 0x3f3f3f3f
#define db double
#define il inline
#define x first
#define y second
#define endl '\n'
const int N=3e5+5;
const int mod=998244353;
int a[30][30],n,ans=0;
unordered_map<int,int>mp[30];
int safe(int x,int y)
{
if(x>=1&&x<=n&&y>=1&&y<=n) return 1;
return 0;
}
void dfs1(int x,int y,int sum)
{
sum^=a[x][y];
if(x+y==n+1)
{
mp[x][sum]++;
return;
}
if(safe(x+1,y)) dfs1(x+1,y,sum);
if(safe(x,y+1)) dfs1(x,y+1,sum);
}
void dfs2(int x,int y,int sum)
{
if(x+y==n+1)
{
ans+=mp[x][sum];
return;
}
sum^=a[x][y];
if(safe(x-1,y)) dfs2(x-1,y,sum);
if(safe(x,y-1)) dfs2(x,y-1,sum);
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>a[i][j];
dfs1(1,1,0);
dfs2(n,n,0);
cout<<ans<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T=1;//cin>>T;
while(T--)
{
solve();
}
return 0;
}
题目2 首先纯暴力 \(O(2^{80})\) ,就给了一个很明确的方向,就是分成四份暴搜。首先对于每次向左/右转,一定改变方向是与 \(x/y\) 轴平行。因此将初始序列分成奇偶位置两个数组分别暴搜;其次对于分完的数组在进行双向搜索,前半部分暴搜的结果存入一个 \(map\) ,在对后半部分进行暴搜时,对于每一个结果 \(res\) ,查询 \(map\) 中是否存在 \(x/y-res\) 。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define inf 0x3f3f3f3f
#define db double
#define il inline
#define x first
#define y second
#define endl '\n'
const int N=2e5+5;
const int mod=998244353;
int a[100],ji[50],ou[50],q[25],h[25];
int n,x,y;
vector<int>v;
int op(int b[],int xy,int cd)
{
v.clear();
memset(q,0,sizeof q);
memset(h,0,sizeof h);
int s1=(n+3)/4,s2=cd-(n+3)/4;
for(int i=1;i<=s1;i++) q[i]=b[i];
for(int i=s1+1;b[i]!=0;i++) h[i-s1]=b[i];
unordered_map<int,int>mp,vis;
for(int s=0;s<(1<<(s1));s++)
{
int sum=0;
for(int i=0;i<(n+3)/4;i++)
{
if(s>>i&1) sum+=q[i+1];
else sum-=q[i+1];
}
vis[sum]=1;
mp[sum]=s;
}
for(int s=0;s<(1<<s2);s++)
{
int sum=0;
for(int i=0;i<s2;i++)
{
if(s>>i&1) sum+=h[i+1];
else sum-=h[i+1];
}
if(vis[xy-sum])
{
int t=mp[xy-sum];
for(int i=0;i<s1;i++) v.push_back(t>>i&1);
for(int i=0;i<s2;i++) v.push_back(s>>i&1);
return 1;
}
}
return 0;
}
void solve()
{
cin>>n>>x>>y;
//奇数对应y,偶数对应x
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(i&1) ji[(i+1)/2]=a[i];
else ou[i/2]=a[i];
}
if(op(ji,y,(n+1)/2))
{
vector<int>j=v;
if(op(ou,x,n/2))
{
vector<int>o=v;
cout<<"Yes"<<endl;
//cout<<j.size()<<" "<<o.size()<<endl;
//ls表示当前正方向,1右,2上,3左,4下
//j和o中1表示向上、右走
int cnt=0,ls=1;
for(int i=1;i<=n;i++)
{
if(i&1)
{
if(j[cnt]==1) //上
{
if(ls==1) cout<<'L';
else if(ls==3) cout<<'R';
ls=2;
}
else if(j[cnt]==0) //下
{
if(ls==1) cout<<'R';
else if(ls==3) cout<<'L';
ls=4;
}
}
else
{
if(o[cnt]==1) //右
{
if(ls==2) cout<<'R';
else if(ls==4) cout<<'L';
ls=1;
}
else if(o[cnt]==0) //左
{
if(ls==2) cout<<'L';
else if(ls==4) cout<<'R';
ls=3;
}
cnt++;
}
}
return;
}
}
cout<<"No"<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T=1;//cin>>T;
while(T--)
{
solve();
}
return 0;
}

浙公网安备 33010602011771号