这道题,居然用错误的方法也可以AC,好吧,我看了比人写的代码,自己弄个数据进去了,好多wa了.
http://poj.org/problem?id=1699
题意是给你很多子序列,让你求最短父序列.
先说这道题的思路:
先预处理出来每两个子序列a,b,a添加到b后面最少添加多少个字符,并保存到add[a][b].
用dfs处理一下,枚举顺序,既然我们已经枚举顺序了,所以我们dfs的时候只需考虑b加到a后面就可以了,那a加到b后面的情况呢?因为是dfs所以肯定会遍历到,所以
我们只要默认添加在后面就好啦
为什么这样的算法可以呢?我一开始是感觉不可以的
以为这个是两两判断的所以
例如这个数据
3
ABC
A
B
这样就会出错,答案变成4,其实应该是5
其实我们只要这样做就可以了
dfs的时候记录这个决策前面的那个字符串的编号,为pre,如果add[pre][i] ==0 那就是说i串可以被pre串完全容纳,位置有可能是在前面,比如pre串为ABCD ,i串为ABC,
那么后面的状态还是得依靠前面的pre串,来,所以pre不改变,那么不等于0呢,ABC CD ,那当然是ABCD所以后面的要和CD比较,要特别注意这点,
虽然不注意也可以AC,估计是题的#include <iostream>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <string>
using namespace std;
const int MAXN=11;
bool vis[MAXN];
int n;
int len;
string str[MAXN];
int add[MAXN][MAXN];
int pos[MAXN],order[MAXN];
int cal(string &a,string &b)
{
int alen=a.size(),blen=b.size();
for(int i=0; i<a.size(); i++)
{
bool ok=true;
for(int j=0;j<blen && i+j<alen;j++)
{
if(a[j+i]!=b[j])
{
ok=false;
break;
}
}
if(ok)
return max(i+blen-alen,0);
}
return blen;
}
void dfs(int pre,int cnt,int sum)
{
if(sum>=len) return ;
if(cnt==n)
{
len=min(len,sum);
return ;
}
for(int i=0; i<n; i++)
{
if(!vis[i])
{
vis[i]=true;
if(pre!=-1)
if(add[pre][i]!=0)
dfs(i,cnt+1,sum+add[pre][i]);
else
dfs(pre,cnt+1,sum);
else
dfs(i,cnt+1,sum+str[i].size());
vis[i]=false;
}
}
}
int main()
{
// freopen("in","r",stdin);
int t;
scanf("%d",&t);
while(t--)
{
len=1<<30;
memset(vis,0,sizeof(vis));
scanf("%d",&n);
for(int i=0; i<n; i++) cin>>str[i];
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
if(i!=j)
add[i][j]=cal(str[i],str[j]);
dfs(-1,0,0);
cout<<len<<endl;
}
return 0;
}