poj2817狀態壓縮DP

//輸出最大的與前一個字符相同的個數之和
//184K 0MS 
//主要要理解是狀態壓縮DP,狀態是是否選擇了該字符
//並且保存狀態時候因爲字符之間有順序,所有需要保存最後一個字符
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;

#define  MAXN  12
static int N;
static char words[MAXN][MAXN];
static int len[MAXN][MAXN];
static int dp[1050][MAXN];//表示是否有該狀態以及當前狀態下最後一個字符

static int calcNums(int i,int j)
{
	int k1,k2;
	k1 = k2 = 0;
	int len1 = strlen(words[i]);
	int len2 = strlen(words[j]);
	int ret = -1;
	for (k1=0;k1<len2;++k1)
	{
		int tmp = 0;
		int k3;
		for (k2=k1,k3=0;k2<len2&&k3<len1;++k2,++k3)
			if (words[i][k3]==words[j][k2])tmp++;
		if (tmp>ret)
			ret = tmp;
	}
	for (k1=0;k1<len1;++k1)
	{
		int tmp = 0;
		int k3;
		for (k2=k1,k3=0;k2<len1&&k3<len2;++k2,++k3)
			if (words[i][k2]==words[j][k3])tmp++;
		if (tmp>ret)
			ret = tmp;
	}

	return ret;
}

static void init()
{
	memset(len,0,sizeof(len));
	for (int i=0;i<N;++i)
	{
		for (int j=i+1;j<N;++j)
		{
			len[i][j] = len[j][i] = calcNums(i,j);
		}
	}
}

static void DP()
{
	memset(dp,0,sizeof(dp));
	for (int s=0;s<(1<<N)-1;++s)
	{
		for (int i=0;i<N;++i)//選擇當前狀態的最後一個字符
		{
			if(s&(1<<i))//如果有該狀態
			for (int j=0;j<N;++j)
			{
				if (i!=j&&(s&(1<<j))==0)
				{
					dp[s|(1<<j)][j] = max(dp[s|(1<<j)][j],dp[s][i]+len[i][j]);
				}
			}
		}
	}

	int ans = 0;
	for (int i=0;i<N;++i)
	{
		if (dp[(1<<N)-1][i]>ans)
		 ans = dp[(1<<N)-1][i];
	}
	printf("%d\n",ans);
}
int main()
{
	while(scanf("%d",&N)&&N)
	{
		for (int i=0;i<N;++i)
			scanf("%s",words[i]);
		init();
		DP();
	}

	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章