codeforces 543C C. Remembering Strings

原创 2015年11月20日 16:28:20

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)
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

codeforces 543C C. Remembering Strings(状态压缩dp)

题目链接:codeforces 543C题目大意:给出n个长度为m的字符串,要求每个字符串必须有一位是区别于其他字符串的,我们修改某个字符串的某一位有一个固定的花费,问修改成符合要求的字符串的最小花费...

[Codeforces 543C] Remembering Strings (状压DP)

Codeforces - 543C 给定 NN 个长度皆为 MM 的字符串,其中 1≤N,M≤201\le N,M\le 20 将第 ii 个字符串的第 jj 为修改成其他字符需要代价 ai...

Codeforces 543C Remembering Strings 题解

Codeforces 543C题解

codeforces #302 Remembering Strings (dp)

题目:http://codeforces.com/contest/544/problem/E 题意:给定n个长度为m的字符串。为了让每个字符串变为独特的(该字符串的某一个位置存在一个字符ch,其他串...
  • w20810
  • w20810
  • 2015年11月12日 16:41
  • 294

Codeforces Round #302 (Div. 2) E. Remembering Strings(状压dp)

E. Remembering Strings time limit per test 2 seconds memory limit per test 256 megabytes...

Codeforces544E:Remembering Strings(状态压缩)

You have multiset of n strings of the same length, consisting of lowercase English letters. We will ...

Codeforces 482C Game with Strings

Game with Str You play the game with your friend. The description of this game is listed below.Your...

【Codeforces】 477C Dreamoon and Strings

dp[i][j] 记录经过i个zi

CodeForces 482C Game with Strings

题意: n个长为m的字符串  等概率的藏起来一个串  然后游戏者来猜藏起来的串是什么  每一步游戏者可以等概率的询问字符串的一个位置  再不断的知道一些位置后  游戏者就可以确定藏起来的串是什么  ...

Codeforces 482C Game with strings

题意:给你n个长度为l的字符串,1
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:codeforces 543C C. Remembering Strings
举报原因:
原因补充:

(最多只允许输入30个字)