CSU 1690 期望DP + 数据结构

/*
首先题目你要理解清楚
对于每个一行的文本串,最后一个字符串是前面的问句的答案
每次可以在一个句子的一半打断他进行抢答
问最有得分的期望值

建一个字典树,字典树上的点存储的是字符串
但是本题奇特的方式在在于字典树上存储了两个值
    一个是正常的文本串顺序,用于遍历和存储文本串
    一个是对于每个句子的答案,有多少个句子可以在这个点回答此答案

最后按照期望DP的方式求解
标程写成递归就直接照搬了,实际上可以写成循环结构

*/

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100000 + 5;
struct Node
{
    map<string,int> next;
    map<string,int> answer;
    double pro;
    int tot;
    void clear() {next.clear(); tot = 0; answer.clear();}
}node[MAXN];
char str[MAXN];
double solve(int i, vector<double>::iterator it, int left)
{
//    printf("i = %d\n", i);
    if(left == 0) return 0;
    double ans1 = node[i].pro + *it;
    double ans2 = 0;
    for(auto v : node[i].next) {
        ans2 += solve(v.second, it + 1, left - 1) * node[v.second].tot;
    }
    return max(ans1, ans2 / node[i].tot);
}
int main()
{
    int t, n;
    while(scanf("%d%d", &t, &n) != EOF) {
        cin.getline(str, MAXN);
        int cnt = 0;
        node[cnt].clear();
        for(int j = 0 ; j < n ; j++){
            cin.getline(str, MAXN);
            string temp = "";
            int index = 0;
            string aanswer = "";
            for(int i = strlen(str) - 1 ; i >= 0 ; i--) {
                if(str[i] == ' ') break;
                else aanswer += str[i];
            }
//            cout << " aanswer = " << aanswer << endl;
            node[0].answer[aanswer]++;
            for(int i = 0 ; str[i] != '\0' ; i++){
                if(str[i] != ' ') temp += str[i];
                else{
                    if(node[index].next.count(temp) == 0){
                        node[index].next[temp] = ++cnt;
                        node[cnt].clear();
                    }
                    node[index].tot++;
                    index = node[index].next[temp];
                    node[index].answer[aanswer]++;
                    temp = "";
                }
            }
            node[index].tot++;
//            temp += str[i];
//            if(node[index].next.count(temp) == 0){
//                node[index].next[temp] = ++cnt;
//                node[cnt].clear();
//            }
//            node[index].tot++;
//            index = node[index].next[temp];
//            node[index].tot++;
        }
        for(int i = 0 ; i <= cnt ; i++){
                int mmax = 0;
                int sum = 0;
                for(auto v : node[i].answer) mmax = max(mmax, v.second), sum += v.second;
                node[i].tot = sum;
                node[i].pro = 1.0 * mmax / node[i].tot;
        }
//        for(int i = 0 ; i <= cnt ; i++)
//            printf("i = %d, pro = %f, tot = %d\n", i, node[i].pro, node[i].tot);
        vector <double> best(t + 1);
        for(int i = t - 1 ; i >= 0 ; i--)
            best[i] = solve(0, best.begin() + i + 1, t - i);
        printf("%.10f\n", best[0]);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值