题意:给定你一些字符串和每个字符修改成任意字符的花费。要求使得每个字符串都存在一个在其j列上唯一的字符。
思路:如果要使得i行j列的字符唯一,有两种方式,一种是改变这个字符,一种是改变该列上其他所有的字符。用状态压缩存储有哪些行的字符串不存在唯一的字符,然后逐一去进行上述两种操作。
AC代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char s[25][25];
int n,m,dp[1100000],num[25][25],INF=1e9,MAXS;
int POW[25],MS[25][25],cost[25][25];
void init()
{
int i,j,k,S;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
MS[i][j]=MAXS;
for(k=1;k<=n;k++)
if(s[i][j]==s[k][j])
{
MS[i][j]-=POW[k];
if(k!=i)
cost[i][j]+=num[k][j];
}
}
}
int main()
{
int i,j,k,ret,S,S2;
bool flag;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
scanf("%s",s[i]+1);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&num[i][j]);
POW[1]=1;
for(i=2;i<=23;i++)
POW[i]=POW[i-1]*2;
MAXS=POW[n+1]-1;
init();
ret=MAXS;
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
flag=true;
for(k=1;k<=n;k++)
if(s[i][j]==s[k][j] && i!=k)
flag=false;
if(flag)
{
ret-=POW[i];
break;
}
}
}
dp[ret]=0;
for(S=0;S<ret;S++)
dp[S]=INF;
for(S=ret;S>0;S--)
if(dp[S]<INF)
{
for(i=1;i<=n;i++)
if(S&POW[i])
{
for(j=1;j<=m;j++)
{
S2=S-POW[i];
dp[S2]=min(dp[S2],dp[S]+num[i][j]);
S2=S&MS[i][j];
dp[S2]=min(dp[S2],dp[S]+cost[i][j]);
}
}
}
printf("%d\n",dp[0]);
}