【ZOJ 3502】Contest

题意

  n个问题,解决的顺序影响正确的概率,无论之前解决的问题是否答对,当前问题 j 答对概率为max{a[i][j]} (i为解决过的问题)。求答对题目的最大期望和对应的答题顺序。T组测试,T (0 < T ≤ 100), n (0 < n ≤ 10)。

分析

  n那么小,就想到状态压缩DP(我不会dfs做这题)

  假设当前状态是 i , i 对应的01串的1代表已经解决的问题,0代表尚未解决的,那么它肯定是由某个已解决的问题还没解决的状态转移过来的,也就是由其中一个1变为0的状态。所以我们枚举它里面的每个1,i&(1<<l) ==1 表示第l个数字是1, j = i-(1<<l) 得到 j 状态。

  dp表示状态i的期望,dp[i]=dp[j] + max(a[i][j]) 。因为多答出一题,期望就增加(1*答出这题的概率)。

  同时每个状态用d储存答题顺序(期望最大且字典序最小的答题顺序)。

  这句判断字典序:ex==dp[i] && d[i]>=d[i-(1<<l)] //如果新的dp[i-(1<<l)]的字典序比较小,dp[i]更新。因为一开始d都是0,所以要用≥,不然第一个样例就不会输出A。

  注意如果计算的时候用浮点数,比较大小还要设置个精度。也可以直接储存整数,最后除以100化为 小数。

代码

#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

int t,n;
int a[15][15];
int dp[1050];
string d[1050];

int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                scanf("%d",&a[i][j]);
        d[0]="";
        memset(dp,0,sizeof(dp));
        for(int i=1; i<(1<<n); i++)
            for(int l=0; l<n; l++)
                if (i&(1<<l))// solve l
                {
                    int ex=0;
                    for(int u=0; u<n; u++)
                    {
                        if(i&(1<<u) && a[u][l]>ex)//u have been solved
                        {
                            ex=a[u][l];
                        }
                    }
                    ex+=dp[i-(1<<l)];
                    char now='A'+l;//第l个问题的字母表示
                    if(ex>dp[i] || ex==dp[i] && d[i]>=d[i-(1<<l)])
                    {
                        d[i]=d[i-(1<<l)]+now;
                        dp[i]=ex;
                    }
                }
        double ans=dp[(1<<n) - 1]*1.0/100;

        printf("%.2lf\n",ans);
        cout<<d[(1<<n) - 1]<<endl;
    }
    return 0;
}

 

  

posted @ 2016-02-17 02:28  水郁  阅读(200)  评论(0编辑  收藏  举报
……