codeforces round# 302 (div1 C) (状压dp)

来源:互联网 发布:js undefined判断 编辑:程序博客网 时间:2024/05/22 16:41

本题目的意思是给定n(n<=20)行长度都为过m(m<=20)的字符串,并且给定一个n*m的数字矩阵,cost(i,j)为将第i行第j个字母修改成任意字母的代价。

求用最小的代价让所有的字符串,都存在一个位置,在同列中没有和它相同的字符。

考虑d[ s ]代表状态s下(其中1代表该位置已经唯一,0反之)还需的最小代价,

转移只有两种,找到最小的没被唯一化得位置p, 枚举修改位置j, 可以 (1)修改j本身   或者  ( 2 )  将j列里所有与该位置第j列有相同字符的修改费用加起来减去一个最大值。

因为左右的可行性转移只有这两种;

还有一个问题 , 比如 n = 4, m = 4,   其中 字符 s[ 1 ][ 3 ] = s[ 2 ][ 3 ] = s[ 3 ][ 3 ];  那么如果直接修改1,3将第一行唯一化,到后面,决策3时采用了(2 ),那么导致唯一化1的费用可能被计算两边,这个问题不需要担心,因为有比他更优且不产生矛盾的解存在,且同过这种转移可以计算到。

//#pragma comment(linker, "/STACK:1024000000,1024000000")#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <set>#include <map>#include <string>#include <list>#include <cstdlib>#include <queue>#include <stack>#include <cmath>#include <bitset>#include <cassert>#define ALL(a) a.begin(), a.end()#define clr(a, x) memset(a, x, sizeof a)#define fst first#define snd second#define pb push_back#define lowbit(x) (x&(-x))#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define rep1(i,x,y) for(int i=x;i<=y;i++)#define rep(i,n) for(int i=0;i<(int)n;i++)using namespace std;const double eps = 1e-10;typedef long long LL;typedef long long ll;typedef pair<int, int> pii;const int oo =0x3f3f3f3f;const int N = 25;char s[N][N];int cost[N][N],sum[N][N],mask[N][N];int n,m;int d[1<<20];int main(){   scanf("%d %d",&n,&m);   rep(i,n) scanf("%s",s[i]);   rep(i,n) rep(j,m) scanf("%d",&cost[i][j]);   rep(i,n) rep(j,m){      int max_ = 0;      sum[i][j] = mask[i][j] = 0;      rep(k,n)if(s[i][j] == s[k][j]){          sum[i][j]+=cost[k][j];          mask[i][j]|=(1<<k);          max_=max(max_,cost[k][j]);      }      sum[i][j]-=max_;   }   int lim = (1<<n)-1;   d[lim] = 0;   for(int s=lim-1;s>=0;s--){      d[s] = oo;      int p = 0;      while(p <n-1 && s&(1<<p)) p++;      for(int i=0;i<m;i++){         d[s] = min(d[s] , d[s|(1<<p)]+cost[p][i]);         d[s] = min(d[s] , d[s|mask[p][i]]+sum[p][i]);      }   }   cout<<d[0]<<endl;   return 0;}



0 0
原创粉丝点击