题意(转):给定n个长度为m的字符串。为了让每个字符串变为独特的(该字符串的某一个位置存在一个字符ch,其他串的这个位置都不存在这个字符ch),你可以改变某些字符串的某些字符。现在告诉你改变每个字符的代价,求让所有的串成为独特的串的最小代价。
两个转移(对某行某列的字母):
1、直接修改本行的字母
2、把所有在该列拥有该字母的行都修改成别的字母。只需修改x-1个,留下权值最大的那个(贪心)。
其中1是必要的。因为你不知道还有哪几行等待被拯救。2是圣母的做法,在待拯救的行占所有行比例较少时适用1。比如对这个:
3 3 abc abc abc 1 100 100 100 1 100 100 100 1
101
3
http://blog.csdn.net/stl112514/article/details/47125275
实际上发生了【某列的某种字母(x个)改变其中x-1个】的操作就不会发生【改变当前单个字母】的操作。所以,不需要考虑修改当前字母后对这一列其他同原字母一样的行的影响,即后者对前者的影响。
#include <bits/stdc++.h> #define ll long long using namespace std; int dp[(1<<20)+5]; string x[22]; int y[22][22]; pair<int,int> w[22][22]; int main(){ int n,m; cin>>n>>m; for(int i=0;i<n;++i){ cin>>x[i]; } for(int i=0;i<n;++i){ for(int j=0;j<m;++j){ cin>>y[i][j]; } } for(int i=0;i<n;++i){ for(int j=0;j<m;++j){ int maxx=0; char c=x[i][j]; if(w[j][c-'0'].second>0) continue; for(int k=0;k<n;++k){ if(x[k][j]==c){ w[j][c-'0'].first+=y[k][j]; w[j][c-'0'].second+=(1<<k); if(y[k][j]>maxx) maxx=y[k][j]; } } w[j][c-'0'].first-=maxx; } } for(int i=1;i<(1<<n);++i) dp[i]=1000000000; for(int i=0;i<(1<<n);++i){ for(int j=0;j<n;++j){ if(i&(1<<j)) continue; for(int k=0;k<m;++k){ //下面两个是冲突的,换句话说,实际上发生了【某列的某种字母(x个)改变其中x-1个】的操作就不会发生【改变当前单个字母】的操作 dp[i|(1<<j)]=min(dp[i|(1<<j)],dp[i]+y[j][k]); int a=w[k][x[j][k]-'0'].first,b=w[k][x[j][k]-'0'].second; dp[i|b]=min(dp[i|b],dp[i]+a); } } } cout<<dp[(1<<n)-1]<<endl; return 0; }