• 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;
    }


  • 相关阅读:
    Git使用
    A star算法
    禅语人生
    android中GridView
    关于Android资源学习
    买了胡百敬老师的<SQL SERVER 2008 管理实战>
    人生七苦
    SQL Server 2008实现"编辑所有行"和"返回所有行"的方法
    陈慧娴《永远是你的朋友》专辑歌词
    SQL Server 2008 Service Pack 1 简体中文补丁包下载
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/5333857.html
Copyright © 2020-2023  润新知