E. Remembering Strings

题目大意

You have multiset of n strings of the same length, consisting of lowercase English letters. We will say that those strings are easy to remember if for each string there is some position i and some letter c of the English alphabet, such that this string is the only string in the multiset that has letter c in position i.

For example, a multiset of strings {"abc", "aba", "adc", "ada"} are not easy to remember. And multiset {"abc", "ada", "ssa"} is easy to remember because:

  • the first string is the only string that has character c in position 3;
  • the second string is the only string that has character d in position 2;
  • the third string is the only string that has character s in position 2.

You want to change your multiset a little so that it is easy to remember. For aij coins, you can change character in the j-th position of the i-th string into any other lowercase letter of the English alphabet. Find what is the minimum sum you should pay in order to make the multiset of strings easy to remember.

数据范围

The first line contains two integers n, m (1 ≤ n, m ≤ 20) — the number of strings in the multiset and the length of the strings respectively. Next n lines contain the strings of the multiset, consisting only of lowercase English letters, each string's length is m.

Next n lines contain m integers each, the i-th of them contains integers ai1, ai2, ..., aim (0 ≤ aij ≤ 106).


题解

被$Lijinnn$讲得贼神,看题解感觉还好。

首先我们需要发现,每一列的每一种字符只可能有两种改动情况。

第一种是把一行的一个字符改掉。

第二种是把这列中的某个字符全都改掉然后留下一个权值最大的。

这是显然的吧....不一定是唯一的但一定是最优的。

接下来就是$dp$了,假设$f[S]$表示状态为$S$的字符串合法了,考虑每列每行都有一种转移方式,暴力转移更新即可。

其实还有一个小优化,但是仗着$CF$评测机快没必要。

是这样的,就是我们发现,先更改某行某列,再更改另一行另一列,和把他们的顺序调换回来是一样的。

所以,我们在用$S$向后转移的时候,只需要任取一个$0$位往后转移即可。

不能保证中间的每一个$f[S]$都是最优的,但是能保证$f[(1<<n)-1]$是最优的,以及更新到最终答案的那一条链是最优的。

代码:(这个小优化就体现在,判断$0$的那个$if$中的那个$break$)

#include <bits/stdc++.h>

#define N 21 

using namespace std;

char s[N][N];

int w[N][N], sm[N][N], cs[N][N];

int dp[1 << N], n, m;

void dispose() {
for (int i = 0; i < n; i ++ ) {
for (int j = 0; j < m; j ++ ) {
int al = 0, mx = 0;
for (int k = 0; k < n; k ++ ) {
if (s[i][j] == s[k][j]) {
al += w[k][j];
mx = max(mx, w[k][j]);
sm[i][j] |= (1 << k);
}
}
cs[i][j] = al - mx;
}
} memset(dp, 0x3f, sizeof dp); dp[0] = 0;
for (int s = 0; s < (1 << n); s ++ ) {
for (int i = 0; i < n; i ++ ) {
if(!(s >> i & 1)) {
for (int j = 0; j < m; j ++ ) {
dp[s | (1 << i)] = min(dp[s | (1 << i)], dp[s] + w[i][j]);
dp[s | sm[i][j]] = min(dp[s | sm[i][j]], dp[s] + cs[i][j]);
}
break;
}
}
}
} int main() {
cin >> 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", &w[i][j]);
}
}
dispose();
printf("%d\n", dp[(1 << n) - 1]);
return 0;
}

小结:最后那个优化的思想其实是很好的,也是一个非常难想到的方法,期待掌握。

[CF544E]Remembering Strings_状压dp的更多相关文章

  1. Codeforces 544E Remembering Strings 状压dp

    题目链接 题意: 给定n个长度均为m的字符串 以下n行给出字符串 以下n*m的矩阵表示把相应的字母改动成其它字母的花费. 问: 对于一个字符串,若它是easy to remembering 当 它存在 ...

  2. Codeforces Round #302 (Div. 1) C - Remembering Strings 状压dp

    C - Remembering Strings 思路:最关键的一点是字符的个数比串的个数多. 然后就能状压啦. #include<bits/stdc++.h> #define LL lon ...

  3. CF543C Remembering Strings 状压dp

    Code: #include <cstdio> #include <algorithm> #include <cstring> #define setIO(s) f ...

  4. BZOJ 1087: [SCOI2005]互不侵犯King [状压DP]

    1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3336  Solved: 1936[Submit][ ...

  5. nefu1109 游戏争霸赛(状压dp)

    题目链接:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1109 //我们校赛的一个题,状压dp,还在的人用1表示,被淘汰 ...

  6. poj3311 TSP经典状压dp(Traveling Saleman Problem)

    题目链接:http://poj.org/problem?id=3311 题意:一个人到一些地方送披萨,要求找到一条路径能够遍历每一个城市后返回出发点,并且路径距离最短.最后输出最短距离即可.注意:每一 ...

  7. [NOIP2016]愤怒的小鸟 D2 T3 状压DP

    [NOIP2016]愤怒的小鸟 D2 T3 Description Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于(0,0)处,每次Kiana可 ...

  8. 【BZOJ2073】[POI2004]PRZ 状压DP

    [BZOJ2073][POI2004]PRZ Description 一只队伍在爬山时碰到了雪崩,他们在逃跑时遇到了一座桥,他们要尽快的过桥. 桥已经很旧了, 所以它不能承受太重的东西. 任何时候队伍 ...

  9. bzoj3380: [Usaco2004 Open]Cave Cows 1 洞穴里的牛之一(spfa+状压DP)

    数据最多14个有宝藏的地方,所以可以想到用状压dp 可以先预处理出每个i到j的路径中最小权值的最大值dis[i][j] 本来想用Floyd写,无奈太弱调不出来..后来改用spfa 然后进行dp,这基本 ...

随机推荐

  1. Laravel中Contracts的理解和使用

    Laravel 的 Contracts 是一组定义了框架核心服务的接口.说白了就是一组接口.使用它就是为了降低耦合性. 即便如此,是不是也有同学会搞不清楚Contracts在lavarel体系中的到底 ...

  2. (十七)线程,connect的第五个参数

    采用多线程,将需要处理的后台数据放入子线程,为了能够跨线程调用,一种方法是使用类似线程锁对线程进行保护,另外一种方法使用Qt的信号槽机制.Qt的信号槽机制采用connect函数进行连接,connect ...

  3. Python基础之range()

    range:指定范围,生成指定数字. 1. range() for i in range(1, 10): print(i) 执行结果为: 1 2 3 4 5 6 7 8 9 2. range()步长 ...

  4. Robot Framework(七)创建用户关键字

    2.6创建用户关键字 关键字表用于通过将现有关键字组合在一起来创建新的更高级别关键字.这些关键字称为用户关键字,以区别于 测试库中实现的最低级库关键字.创建用户关键字的语法与创建测试用例的语法非常接近 ...

  5. HDU 4496 D-City —— (并查集的应用)

    给出n个点和m条边,一条一条地删除边,问每次删除以后有多少个联通块. 分析:其实就是并查集的应用,只是前一阵子一直做图论思路一直囿于tarjan了..方法就是,记录每一条边,然后从最后一条边开始不断的 ...

  6. mysql 查看当前正在执行的语句

    查看当前正在执行的语句 show processlist:show processlist; 结束正在执行的语句进程 kill 进程id

  7. OUC_TeamTraining_#1 720

    D - The Mirror of Galadriel Time Limit:2000MS     Memory Limit:0KB     64bit IO Format:%lld & %l ...

  8. 解决Linux下Firefox无法启动的问题

    在linux下使用Firefox连接被测系统的GUI,一次偶然操作导致linux系统运行缓慢,Firefox无法正常操作,从system monitor 杀掉所有java进程将Firefox强行关闭. ...

  9. 黑马vue---17、vue中通过属性绑定绑定style行内样式

    黑马vue---17.vue中通过属性绑定绑定style行内样式 一.总结 一句话总结: 如果属性名中带有短线必须加引号,比如: h1StyleObj: { color: 'red', 'font-s ...

  10. Failed to execute aapt

    Failed to execute aapt 没错,看到这个表示你的资源出错了.不用想别的. 比如: Failed to execute aapt com.android.ide.common.pro ...