[問題描述]
Io和Ao在玩一個單詞遊戲。他們輪流說出一個僅包含元音字母的單詞,並且後一個單詞的第一個字母必須與前一個單詞的最後一個字母一致。遊戲可以從任何一個單詞開始。
任何單詞禁止說兩遍,遊戲中只能使用給定詞典中含有的單詞。
遊戲的複雜度定義爲遊戲中所使用的單詞的長度總和。
編寫程序求出使用一本給定的詞典來玩這個遊戲所能達到的遊戲最大可能複雜度。
數據規模限制:單詞總數不超過16,單詞長度不超過100。
分析:
集合的表示方法:將一個集合與一個二進制數對應,再將二進制數與十進制數對應。爲了方便操作,單詞的編號也可以從1…N,改成0…N-1。比如:集合[1,4,5]->集合[0,3,4]->11001(2)->2^0+2^3+2^4=25。本題目中的檔次總數不超過16,就可以設置長度爲16的二進制比特串。這樣操作不但節省了空間,而且在進行集合操作時可以用位操作,又節省了時間。
//============================================================================
// Name : word.cpp
// Author : Gecko
// Version : 1.0
// Copyright : Your copyright notice
// Description : 記憶搜索,以單詞爲例。本體技巧除了記憶搜索外還有使用二進制表示集合關係
//============================================================================
#include <stdio.h>
#include <string.h>
const int maxn = 16;
const int pow[17] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536};
const int maxtotal = 65535;
char *w[maxn];//單詞
int a[maxn][maxn];//單詞之間的關係
int c[maxn][maxtotal];//最優值
int len[maxn];//單詞長度
int n,i,j,ans,temp,total;
int work(int i,int j)
{
int j1,k,temp;
if (c[i][j])
return c[i][j];
j1 = j-pow[i];
for(k=0;k<n;k++)
{
if(a[i][k] && pow[k] && j)
{
temp = work(k,j1)+len[i];
if (temp>c[i][j])
c[i][j] = temp;
}
}
return c[i][j];
}
int main()
{
scanf("%d",&n);
for (i=0;i<n;i++)
{
scanf("%s",w[i]);
len[i] = strlen(w[i]);
}
memset(a,sizeof(a),0);
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(i!=j && (w[i][len[i]] == w[j][1]))
a[i][j] = 1;
total = pow[n]-1;
memset(c,sizeof(c),0);
for (i=0;i<n;i++)
{
c[i][pow[i]] = len[i];
}
ans = 0;
for(i=0;i<n;i++)
{
for(j=0;j<=total;j++)
{
if (pow[i] && j)
{
temp = work(i,j);
if (temp>ans)
{
ans = temp;
}
}
}
}
printf("%d",ans);
return 0;
}