这题学到了一个方法吧:
如果要枚举集合S的子集:
for(int i = S; i > 0; i=(i-1)&S)
如果要枚举包含S的集合:
for(int i = S; i < (1<<n); i = (i+1)|S)
很巧的方法,以前从未见过,在这mark下了。
下面给出两种方法的代码:
记忆化搜索:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define N (1<<16)
int n;
char a[20];
int is[N], dp[N];
int is_pl(int s)
{
vector<int> q;
for(int i = 0; i < n; i++)
if(s&(1<<i))q.push_back(i);
for(int i = 0; i < q.size()/2; i++)
if(a[q[i]]!=a[q[q.size()-i-1]])
return 0;
return 1;
}
int dfs(int s)
{
if(dp[s]!=-1)return dp[s];
dp[s]=0x7ffffff;
for(int i = s; i > 0; i=(i-1)&s)
if(is[i])dp[s]=min(dp[s],dfs(s-i)+1);
return dp[s];
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
memset(is,0,sizeof(is));
memset(dp,-1,sizeof(dp));
scanf("%s",a);
n=strlen(a);
for(int i = 1; i < (1<<n); i++)
is[i]=is_pl(i);
dp[0]=0;
printf("%d\n",dfs((1<<n)-1));
}
return 0;
}
宽搜
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#define N (1<<16)
int n;
char a[20];
int is[N], dp[N];
int is_pl(int s)
{
vector<int> q;
for(int i = 0; i < n; i++)
if(s&(1<<i))q.push_back(i);
for(int i = 0; i < q.size()/2; i++)
if(a[q[i]]!=a[q[q.size()-i-1]])
return 0;
return 1;
}
queue <int> Q;
void bfs(int x)
{
Q.push(x);
dp[x]=0;
while(!Q.empty())
{
int u=Q.front();
Q.pop();
if(u==0)return ;
for(int i = u; i > 0; i=(i-1)&u)
{
if(dp[u-i]==-1&&is[i])
{
Q.push(u-i);
dp[u-i]=dp[u]+1;
}
}
}
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
while(!Q.empty())Q.pop();
memset(is,0,sizeof(is));
memset(dp,-1,sizeof(dp));
scanf("%s",a);
n=strlen(a);
for(int i = 1; i < (1<<n); i++)
is[i]=is_pl(i);
bfs((1<<n)-1);
printf("%d\n", dp[0]);
}
return 0;
}
运行时间都是1秒