zoukankan      html  css  js  c++  java
  • Codeforces 544E Remembering Strings 状压dp

    题目链接

    题意:

    给定n个长度均为m的字符串

    以下n行给出字符串

    以下n*m的矩阵表示把相应的字母改动成其它字母的花费。

    问:

    对于一个字符串,若它是easy to remembering 当 它存在一个字母。使得这个字母在这一列是独一无二的。

    要使得n个字符串都是easy to remembering 的最小花费。

    第一个例子是把第一列的4个a中3个a改动成别的字母。所以花费为3.

    思路:

    显然是个状压dp,但须要一点转化。

    首先得到一个结论:

    对于某一列,设这一列的字母是 a,a,b,b,a,d,c··· 

    随意改动某种字母,都能使得包含该种字母的字符串变成unique

    instance: 把全部的a字母都改动为别的字母,一定能使得改动后的字母与同列的其它字母不反复。

    由于最多仅仅有20个字符串,也就是改动后的字母种类至多仅仅有20种。

    然后状压已经easy to remembering的字符串的最小花费。

    dp[i] 表示已经easy to remembering 的字符串状态为i时的最小花费。

    两个转移:

    1、直接改动字母

    2、把这一列中全部与这个字母同样的字母都改动成别的字母。

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

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

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

    #include <iostream>
    #include <string>
    #include <vector>
    #include <cstring>
    #include <cstdio>
    #include <map>
    #include <queue>
    #include <algorithm>
    #include <stack>
    #include <cstring>
    #include <cmath>
    #include <set>
    #include <vector>
    using namespace std;
    template <class T>
    inline bool rd(T &ret) {
    	char c; int sgn;
    	if (c = getchar(), c == EOF) return 0;
    	while (c != '-' && (c<'0' || c>'9')) c = getchar();
    	sgn = (c == '-') ? -1 : 1;
    	ret = (c == '-') ? 0 : (c - '0');
    	while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
    	ret *= sgn;
    	return 1;
    }
    template <class T>
    inline void pt(T x) {
    	if (x <0) {
    		putchar('-');
    		x = -x;
    	}
    	if (x>9) pt(x / 10);
    	putchar(x % 10 + '0');
    }
    typedef long long ll;
    typedef pair<ll, ll> pii;
    const int inf = 1e9;
    const int N = 21;
    int n, m;
    char s[N][N];
    int a[N][N];
    int dp[1 << N];
    int bit[N][N], cost[N][N];
    int main() {
    	rd(n); rd(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++)rd(a[i][j]);
    	for (int i = 0; i < n; i++)
    		for (int j = 0; j < m; j++) 
    		{
    			int ans = 0, maxn = -inf;
    			for (int k = 0; k < n; k++)
    				if (s[i][j] == s[k][j])
    				{
    					ans += a[k][j];
    					maxn = max(maxn, a[k][j]);
    					bit[i][j] |= 1 << k;				
    				}
    			ans -= maxn;
    			cost[i][j] = ans;
    		}
    	for (int i = 1; i < (1 << n); i++)dp[i] = inf; 
    	dp[0] = 0;
    	for (int i = 0; i < (1 << n); i++)
    	{
    		for (int j = 0; j < n; j++)
    			if ((i & (1 << j)) == 0)
    			{
    				for (int k = 0; k < m; k++)
    				{
    					dp[i | (1 << j)] = min(dp[i | (1 << j)], dp[i] + a[j][k]);
    					dp[i | bit[j][k]] = min(dp[i | bit[j][k]], dp[i] + cost[j][k]);
    				}
    			}
    	}
    	pt(dp[(1 << n) - 1]);
    	return 0;
    }


  • 相关阅读:
    hdu 5045 Contest
    hdu 4068 SanguoSHA
    TSP 旅行商问题(状态压缩dp)
    haoi2015 树上操作
    noi 2015 软件包管理器(树链剖分)
    zjoi2008 树链剖分
    读入优化
    动态规划类型总结
    有关Rujia Liu 动态规划的·一些总结
    输入优化
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/5333857.html
Copyright © 2011-2022 走看看