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. linux系统编程--线程

    安装线程man page,命令:sudo apt-get install manpages-posix-dev 线程概念 什么是线程 LWP:light weight process 轻量级的进程,本 ...

  2. [Luogu] 逛公园

    https://www.luogu.org/problemnew/show/P3953 https://www.zybuluo.com/wsndy-xx/note/1134388 #include&l ...

  3. 【CUDA 基础】5.0 共享内存和常量内存

    title: [CUDA 基础]5.0 共享内存和常量内存 categories: - CUDA - Freshman tags: - 共享内存 - 常量内存 toc: true date: 2018 ...

  4. thinkphp6下载安装与配置图文详细讲解教程(composer下载安装)

    thinkphp6发布也有一段时间了,相对来说比较稳定,是时候学习一下thinkphp6框架,提前学习,到正式发布的时候,可以直接拿来做正式的项目,先人一步.thinkPHP6.0在5.1的基础上对底 ...

  5. axios拦截器使用方法

    vue中axios获取后端接口数据有时候需要在请求开始时显示loading,请求结束后隐藏loading,这时候到每次调接口时都写上有点繁琐,有时候还会漏写. 这时候axios的拦截器就起了作用,我们 ...

  6. 总结调试webview的方式(安卓)

    参考文章: 移动端真机调试指南 Mac 平台 Android 使用 Charles 抓包方法 Charles使用Map Local和Rewrite提高开发效率 通过chrome直接进行调试 chrom ...

  7. json常用的注解

    json注解: 1.@JsonIgnoreProperties: 此注解是类注解,作用是json序列化时将java bean中的一些属性忽略掉,序列化和反序列化都受影响. 写法将此标签加在model ...

  8. Linux孤儿进程与僵尸进程

    1. 基本概念: 孤儿进程:父进程退出,但是其子进程仍然在运行,那么这些子进程被称为孤儿进程:孤儿进程会被init进程收养,并作善后处理: 僵尸进程:一个已经终止,但是其父进程尚未对齐进行善后处理的进 ...

  9. 性能测试 | 系统运行缓慢,CPU 100%,Full GC次数过多问题排查

    处理过线上问题的同学基本上都会遇到系统突然运行缓慢,CPU 100%,以及Full GC次数过多的问题.当然,这些问题的最终导致的直观现象就是系统运行缓慢,并且有大量的报警.本文主要针对系统运行缓慢这 ...

  10. 前端知识点回顾——Nodejs

    Node.js 事件循环机制 setImmediate()是将事件插入到事件队列尾部,主线程和事件队列的函数执行完成之后立即执行setImmediate指定的回调函数,和setTimeout(fn,0 ...