您的位置:首页 > 其它

SRM 542 DIV1 500 StrangeDictionary2

2016-09-13 16:33 309 查看
Task:

给你若干个字符串,然后给它们进行排序,但排序依照的位数是一个随机生成的排列(就是你可能对两个长度为三的字符串,先将它们的第2位进行比较,再比较第1位,再比较第3位才能得到它们的大小关系),那么求出每个字符串的期望排序后在第一位(最小)的可能性,(n<=16)

Solution:

这是一道状压dp题,我们定义dp[S][i]为当前剩下的集合为S,第i个元素可能是最小的可能性,那我们先预处理出如果选第j位进行比较,有哪些字符串会比i小,或者与i相等.如果下一位选第j位,若S&Smaller[j]!=0,则证明选这个是不行的,我们让cnt++,这里的cnt是指这一步我们可以进行的操作总和.而如果S&Equal[j]!=S,则证明选第j位可能使i变的最小,则cnt++,dp[S][i]+=dp[S&Equal[j]][i].最后dp[S][i]/=cnt即可.

这样,我们就推出了dp的转移顺序与方程,然后就能将题目写出来了.

int sz,L,Smaller[55],Equal[55];
double dp[1<<18][18];
vector<double>ans;
vector<string>Words;
double Dp1(int S,int now){
if(dp[S][now]>-0.5)return dp[S][now];
if(S==1<<now)return dp[S][now]=1.0;
if((int)(S&(1<<now))==0)return dp[S][now]=0;
dp[S][now]=0;
int cnt=0;
for(int i=0;i<L;i++){
if((int)(S&Smaller[i])>0)cnt++;
else if((int)(S&Equal[i])!=S){
cnt++;
dp[S][now]+=Dp1((int)(S&Equal[i]),now);
}
}
dp[S][now]/=1.0*cnt;
return dp[S][now];
}
double Dp(int now){
memset(Equal,0,sizeof(Equal));
memset(Smaller,0,sizeof(Smaller));
for(int i=0;i<sz;i++)
for(int j=0;j<L;j++)
if(Words[now][j]>Words[i][j])Smaller[j]|=1<<i;
else if(Words[now][j]==Words[i][j])Equal[j]|=1<<i;
return Dp1((1<<sz)-1,now);
}
class StrangeDictionary2 {
public:
vector <double> getProbabilities(vector <string> words) {
L=words[0].length(),sz=words.size();
for(int i=0;i<1<<sz;i++)
for(int j=0;j<sz;j++)
dp[i][j]=-1;
ans.clear();Words.clear();
for(int i=0;i<sz;i++)Words.push_back(words[i]);
for(int i=0;i<sz;i++)ans.push_back(Dp(i));
return ans;
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: