Description A few kids are standing around an old tree playing a game.
The tree is so huge that each kid can only see the kids close to
him/her.The game consists many ‘turns’. At the beginning of each turn of the
game, a piece of paper is given to a randomly chosen kid. This kid
writes the letter “B” if he is a boy or the letter “G” if a girl. Then
he chooses a direction to pass the paper (clockwise or
counter-clockwise), and gives the paper to his neighbor in that
direction. The kid getting the paper writes down his sex too, and
gives the paper to his neighbor in the same direction. In this way,
the paper goes through the kids one by one, until one kid stops
passing the paper and announces the end of this turn.For example, there are five kids around the tree, and their genders
are shown in Figure-1. The paper first goes to Kid1, after writing a
“B” he passes it to Kid2, and Kid2 to Kid3. After Kid3 writes down a
“G”, she ends up this turn, and we get the paper with a string “BBG”.After N turns, we get N pieces of paper with strings of “B”s and/or
“G”s. One of the kids will get all these papers, and has to figure out
at least how many kids are around the tree playing the game. It’s
known that there are at least two kids. Please write a program to help
him.
Input There are several test cases. Each case starts with a line
containing an integer N, the number of papers (2 <= N <= 16). Each of
the following N lines contains a string on a paper, which is a
nonempty string of letter “B”s and/or “G”s. Each string has no more
than 100 letters.A test case of N = 0 indicates the end of input, and should not be
processed.Output For each test case, output the least possible number of kids in
如果一个串完全包含于另外一个的话,这个串就是没有用的,可以把它删去。接下来的操作都是对于任意一个串不是另一个的子串进行。
最简单的方法就是把所有串按顺序连接,这样结果是串长的总和。为什么答案会变优呢?因为有一些重叠的部分。容易发现,每相邻两个串【注意,只计算相邻的两个】重叠多长,答案就减少多少。
预处理出任意两个串一个接在另一个后面的最大重叠长度,然后用dp[i][j]表示选了集合i中的元素,最后一个是j的最大重叠长度,然后枚举下一个接在后面的字符串。
注意字符串正放和反放的情况【也就是原题中顺时针和逆时针】。
考虑到环,可以强行规定第一个位置放正放的第一个串,然后对答案加上末尾串接正放第一串的重叠长度。
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
using namespace std;
struct seq
{
char s[2][110];
int l;
}a[20],f[20];
int n,n1,ovl[20][2][20][2],dp[1<<17][20][2];
bool out[20];
char temp[110];
void in()
{
int i,j;
for (i=1;i<=n;i++)
{
scanf("%s",a[i].s[0]+1);
a[i].l=strlen(a[i].s[0]+1);
strcpy(temp+1,a[i].s[0]+1);
for (j=1;j<=a[i].l;j++)
a[i].s[1][j]=temp[a[i].l-j+1];
}
}
bool inc(char* s1,int l1,char* s2,int l2)
{
if (l1>l2) return 0;
int i,j;
bool flag;
for (i=1;i+l1-1<=l2;i++)
{
flag=1;
for (j=1;j<=l1;j++)
if (s1[j]!=s2[i+j-1])
{
flag=0;
break;
}
if (flag) return 1;
}
return 0;
}
int cal (char* s1,int l1,char* s2,int l2)
{
int i,j;
bool flag;
for (i=max(1,l1-l2+2);i<=l1;i++)
{
flag=1;
for (j=1;i+j-1<=l1;j++)
if (s2[j]!=s1[i+j-1])
{
flag=0;
break;
}
if (flag) return l1-i+1;
}
return 0;
}
void pre()
{
int i,j,x,y;
n1=0;
memset(out,0,sizeof(out));
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
if (i!=j&&(inc(a[i].s[0],a[i].l,a[j].s[0],a[j].l)||inc(a[i].s[0],a[i].l,a[j].s[1],a[j].l))&&(!out[j]))
out[i]=1;
for (i=1;i<=n;i++)
if (!out[i])
f[n1++]=a[i];
for (i=0;i<n1;i++)
for (x=0;x<2;x++)
for (j=0;j<n1;j++)
for (y=0;y<2;y++)
ovl[i][x][j][y]=cal(f[i].s[x],f[i].l,f[j].s[y],f[j].l);
}
void upd(int &x,int y)
{
if (y>x) x=y;
}
void solve()
{
int i,j,x,y,mx=(1<<n1)-1,tot=0,k,ans;
memset(dp,128,sizeof(dp));
dp[1][0][0]=0;
for (i=1;i<mx;i++)
for (j=0;j<n1;j++)
if (i&(1<<j))
for (x=0;x<2;x++)
for (k=0;k<n1;k++)
if (!(i&(1<<k)))
for (y=0;y<2;y++)
upd(dp[i|(1<<k)][k][y],dp[i][j][x]+ovl[j][x][k][y]);
for (i=0;i<n1;i++)
tot+=f[i].l;
ans=-1;
for (i=0;i<n1;i++)
for (x=0;x<2;x++)
upd(ans,dp[mx][i][x]+ovl[i][x][0][0]);
printf("%d\n",max(2,tot-ans));
}
int main()
{
while (scanf("%d",&n)&&n)
{
in();
pre();
solve();
}
}