关闭

codeforces 543C C. Remembering Strings

199人阅读 评论(0) 收藏 举报
分类:

51nod:好记的字符串


题意:给定n个长度为m的字符串。为了让每个字符串变为独特的(该字符串的某一个位置存在一个字符ch,其他串的这个位置都不存在这个字符ch),你可以改变某些字符串的某些字符。现在告诉你改变每个字符的代价,求让所有的串成为独特的串的最小代价。


分析:定义dp[bitmask],bitmask的二进制中的1表示该位表示的字符串是独特,dp[bitmask]表示到达bitmask这个状态的最小代价。

两个转移:

1、直接修改字母

2、把这一列中所有与这个字母相同的字母都修改成别的字母。

当然可以剩下一个,剩下花费最大的那个即可。

cost[i][j] 就表示除了花费最大的那个 同列中与str[i][j]字母相同的花费和。

bit[i][j] 表示哪些字符串 在第j列 与 a[i][j] 字母相同。

  • 修改第i个字符串的第j个字符时,满足转移方程:
    dp[i][state|(1<<j)]=min{dp[i1][state]+cost[i][j]}
  • 修改一组字符串的第j个字母使他们全部合法的转移方程是: 
    dp[i][state|set]=min{dp[i1][state]+costset[j]}

复杂度是O(2nmn) 

由于state最后是由小变大(或者由大变小),每次枚举state时只要枚举合法的state,所以复杂度优化为O(2nm) 


以下程序里1与0反着写,1代表不是好记的,0代表好记的,这样好写for循环。

虽然3重for循环,实际复杂度O(2nm)

#include <cstdio>
using namespace std;

#define mylen 21
#define maxfigure 1000000000
int n, m;
char s[mylen][mylen];
int c[mylen][mylen];
int f[mylen][mylen];
int bit[mylen][mylen];
int result[(1 << mylen)];

int main()
{
	scanf("%d%d", &n,&m);
	for (int i = 0; i < n; ++i)
	{
		scanf("%s", s[i]);
	}

	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < m;++j)
		{
			scanf("%d", &c[i][j]);
		}
	}

	for (int i = n - 1; i >= 0; --i)			//初始化所有代价
	{
		for (int k = 0; k < m; ++k)
		{
			if (f[i][k])
			{
				bit[i][k] = bit[f[i][k]][k];
				f[i][k] = f[f[i][k]][k];
				continue;
			}

			int tmp = f[i][k] = c[i][k];
			bit[i][k] = (1 << i);

			for (int j = i-1; j >=0; --j)
			{
				if (s[i][k] == s[j][k])
				{
					f[j][k] = i;

					f[i][k] += c[j][k];
					bit[i][k] |= (1 << j);

					if (tmp < c[j][k])
					{
						tmp = c[j][k];
					}
				}
			}
			f[i][k] -= tmp;
			bit[i][k] = (~bit[i][k])&((1 << n) - 1);
		}
	}

	
	int  tmp1 = (1 << n), tmp2, tmp, state, state1;

	for (int i = tmp1-2; i >= 0; --i)
	{
		result[i] = maxfigure;
	}
	result[tmp1 - 1] = 0;

	for (int i = n-1; i >= 0;--i)
	{		
		tmp2 = tmp1 - 1;
		tmp1 = (1 << i);
		state1 = ~tmp1;

		for (int k = 0; k < m;++k)
		{
			for (int j = tmp1; j <= tmp2; ++j)
			{
				state = j&bit[i][k];
				tmp = result[j] + f[i][k];
				if (result[state] > tmp)
				{
					result[state] = tmp;
				}


				state = j & state1;
				tmp = result[j] + c[i][k];
				if (result[state] > tmp)
				{
					result[state] = tmp;
				}
			}
			
		}
	}



	printf("%d", result[0]);

	return 0;
}



O(2nm)
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:37538次
    • 积分:1575
    • 等级:
    • 排名:千里之外
    • 原创:118篇
    • 转载:54篇
    • 译文:0篇
    • 评论:0条