Codeforces544E: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 thei-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.

Input

The first line contains two integers nm (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).

Output

Print a single number — the answer to the problem.

Sample test(s)
input
4 5
abcde
abcde
abcde
abcde
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
output
3
input
4 3
abc
aba
adc
ada
10 10 10
10 1 10
10 10 10
10 1 10
output
2
input
3 3
abc
ada
ssa
1 1 1
1 1 1
1 1 1
output
0

题意:给出n个长为m的字符串,要求通过改变一些字母,来使得每个字符串,在位置i下的字母与其他串都不一样,给出每个位置改变字母的消耗,要求最小消耗

思路:对于每一个行,我们看每个字符在这一列有几个与其相等的字符,我们就使用两种方案,1是改变这个字符,2是改变除了花费最大的其他字符,然后使用状态压缩去枚举所有情况

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <math.h>
#include <bitset>
#include <algorithm>
#include <climits>
using namespace std;

#define LS 2*i
#define RS 2*i+1
#define UP(i,x,y) for(i=x;i<=y;i++)
#define DOWN(i,x,y) for(i=x;i>=y;i--)
#define MEM(a,x) memset(a,x,sizeof(a))
#define W(a) while(a)
#define LL long long
#define N 25
#define MOD 19999997
#define INF 0x3f3f3f3f
#define EXP 1e-8

char str[N][N];
int a[N][N],cost[N][N];
int dp[1<<21],mark[N][N];

int main()
{
    int i,j,k,n,m;
    scanf("%d%d",&n,&m);
    UP(i,0,n-1)
    {
        scanf("%s",str[i]);
    }
    UP(i,0,n-1)
    {
        UP(j,0,m-1)
        {
            scanf("%d",&a[i][j]);
        }
    }
    MEM(mark,0);
    UP(i,0,n-1)
    {
        UP(k,0,m-1)
        {
            int maxn = 0;
            UP(j,0,n-1)
            {
                if(str[i][k]==str[j][k])
                {
                    mark[i][k]|=(1<<j);
                    cost[i][k]+=a[j][k];
                    maxn = max(maxn,a[j][k]);
                }
            }
            cost[i][k]-=maxn;
        }
    }
    int s = (1<<n);
    UP(i,0,s)
    {
        dp[i] = INF;
    }
    int first;
    dp[0] = 0;
    UP(k,0,s-1)
    {

        for(first=0; k&(1<<first); first++);
        UP(i,0,m-1)
        {
            dp[k|(1<<first)] = min(dp[k|(1<<first)],dp[k]+a[first][i]);
            dp[k|mark[first][i]] = min(dp[k|mark[first][i]],dp[k]+cost[first][i]);
        }

    }
    printf("%d ",dp[s-1]);

    return 0;
}


你可能感兴趣的:(codeforces)