题目链接:Click here~~
题意:
有一个长为 m 的 ’*‘ 串M 和 一个长为 n 的包含 ’*‘ 或 '.' 的 串N,每一步可以在任意位置进行匹配,匹配过后 串M 中同为 '*' 的位置会被清空。
问最少多少步能使整个 串M 被清空。
解题思路:
由于 串M 最长20,所以可以用 dp[mask] 表示当前状态为 mask 时候最少几步能到达。
转移方程就是 dp[mask] = min { dp[premask] + 1 },可以用BFS来实现。转移时,注意枚举所有可能匹配的位置。
复杂度大概O(1<<20 * (n+m))。
Ps.加个inline 时间缩短了好多。另外要注意积累一些位运算的技巧。
#include <queue>
#include <string>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
string cut;
int n,m,mask1,mask2;
bool vis[1<<20];
inline void push(queue< pair<int,int> >& Q,pair<int,int>& next,int mask,int mm)
{
next.first = mask ^ mm & mask;
next.first &= (1 << m) - 1;
if(!vis[ next.first ]){
vis[ next.first ] = true;
Q.push(next);
}
}
int bfs()
{
queue< pair<int,int> > Q;
Q.push(make_pair((1<<m)-1,0));
pair<int,int> cur,next;
while(!Q.empty()){
cur = Q.front();
Q.pop();
int mask = cur.first;
next.second = cur.second + 1;
if(mask == 0)
return cur.second;
for(int i=0;i<n;i++){
push(Q,next,mask,mask1 >> i);
push(Q,next,mask,mask2 >> i);
}
for(int i=0;i<m;i++){
push(Q,next,mask,mask1 << i);
push(Q,next,mask,mask2 << i);
}
}
return -1;
}
int main()
{
while(~scanf("%d",&n))
{
cin >> cut >> m;
while(!cut.empty() && cut[0] == '.')
cut.erase(cut.begin()) , n--;
while(!cut.empty() && cut[(int)cut.size()-1] == '.')
cut.erase(cut.begin()+(int)cut.size()-1) , n--;
if(cut.empty())
puts("-1");
else{
memset(vis,false,sizeof(vis));
mask1 = mask2 = 0;
for(int i=0;i<(int)cut.size();i++){
if(cut[i] == '*'){
mask1 |= 1 << i;
mask2 |= 1 << n-1-i;
}
}
printf("%d\n",bfs());
}
}
return 0;
}