codeforces C. Remembering Strings 状态压缩-预处理

来源:互联网 发布:如何把淘宝店开好 编辑:程序博客网 时间:2024/06/06 02:14

状态压缩-预处理

题意:

​ 好记的字符串是n个字符串中,每一个字符串至少有一位是与众不同的。现在给你n个字符串,但是有的字符串不满足与众不同,让你修改某一个或者一些位置的字符串使得满足题意,每一个位置的修改都有对应的花费,问最少的花费是多少。

思路:

​ 之前写过的棋盘问题,条件都是直接看的到的,在进行状态压缩的时候直接可以用到条件,但这种题似乎很难直接想到如何使用条件,不妨先思考如何修改,对于一个字符串,修改自己的某一位的花费是直接可以算的,但是可能会自己修改的花费巨大,大于把与其它字符串同位置的修改的和,所以这两种方式的修改都要进行dp取最优。

​ 第一种很简单不多说。

​ 第二种:当修改i行的某一位的字符时,可以把最大的花费不修改,而修改其它行的此位置的字符,修改完之后,对应的行全部都是满足题意的(因为n小于26)。这些需要的花费和状态通过sum和state数组进行保存。

实现过程:

​ 通过从初始状态依次取最优解,直到所有的状态都是最优的。

  • 遇到此类问题,先思考如何解决,再想如何状态压缩也是另一种很好的思维。
#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int maxn = 25;const int INF = 0x3f3f3f3f;int n,m;int c[maxn][maxn];int sum[maxn][maxn];int state[maxn][maxn];int dp[(1<<21)];char str[maxn][maxn];int main(){    //freopen("in.txt","r",stdin);    scanf("%d%d",&n,&m);    for(int i = 0;i < n; i++) {        scanf("%s",str[i]);    }    for(int i = 0;i < n; i++) {        for(int j = 0;j < m; j++) {            scanf("%d",&c[i][j]);        }    }    for(int i = 0;i < n; i++) {        for(int k = 0;k < m; k++) {            int M = 0;            for(int j = 0;j < n; j++) {                if(str[i][k] == str[j][k]) {                    M = max(M,c[j][k]);                    sum[i][k] += c[j][k];                    state[i][k] |= (1<<j);                }            }            sum[i][k] -= M;        }    }    memset(dp,INF,sizeof(dp));    int pos = (1<<n)-1;    dp[0] = 0;    for(int i = 0;i <= pos; i++) {        for(int j = 0;j < n; j++) {            if(!(i&(1<<j))) {                int now = (1<<j);                for(int k = 0;k < m; k++) {                    dp[i|now] = min(dp[i|now],dp[i] + c[j][k]);                    dp[i|state[j][k]] = min(dp[i|state[j][k]],dp[i]+sum[j][k]);                }            }        }    }    printf("%d\n",dp[(1<<n)-1]);    return 0;}
原创粉丝点击