Codeforces 543C Remembering Strings(DP)

题意比较麻烦

见题目链接

 

 


 

Solution:

   非常值得注意的一点是题目给出的范围只有20,而众所周知字母表里有26个字母。于是显然对一个字母进行变换后是不影响到其它字符串的。

         20的范围恰好又是常见状压DP的范围,所有状态压缩后用DP[sta]代表对应位的字符串已经满足要求的最小花费。

         转移的时候,对一个字符串,逐列判断使它满足条件的最小花费,记录使用这个策略对sta的影响。

         即对同一列有两种情况,直接变换该字符串的这一位,或者变换这一列的sum-1个有相同字符的位置(去掉代价最大的)。

#include <bits/stdc++.h>

using namespace std;



int dp[1 << 20];

int cost[30][30], f[30][30], change[30][30];



int n, m;

char s[30][30];



inline void getCost ()

{

    for (int k = 0; k < n; ++k)

    {

        for (int i = 0; i < m; ++i)

        {

            int sum = 0, tem = 0;

            f[i][k] = 0x7fffffff;

            for (int j = 0; j < n; ++j)

            {

                if (s[j][i] == s[k][i])

                {

                    change[i][k] |= 1 << j;

                    sum += cost[j][i];

                    tem = max (tem, cost[j][i]);

                }

            }

            f[i][k] = min (f[i][k], sum - tem);

        }

    }

}



int main()

{

    ios::sync_with_stdio (0);



    cin >> n >> m;

    for (int i = 0; i < n; ++i)

        cin >> s[i];



    for (int i = 0; i < n; ++i)

        for (int j = 0; j < m; ++j)

            cin >> cost[i][j];



    getCost();



    memset (dp, 0x3f, sizeof dp);

    dp[0] = 0;

    for (int st = 0; st < (1 << n); ++st)

    {

        for (int i = 0; i < n; ++i)

        {

            if ( (st & 1 << i) == 0)

            {

                for (int j = 0; j < m; ++j)

                {

                    dp[st | change[j][i]] = min (dp[st | change[j][i]], dp[st] + f[j][i]);

                    dp[st | 1 << i] = min (dp[st | 1 << i], dp[st] + cost[i][j]);

                }

                break;

            }

        }

    }

    cout << dp[ (1 << n) - 1] << endl;

}
View Code

 

你可能感兴趣的:(codeforces)