4899: 记忆的轮廓

4899: 记忆的轮廓

Time Limit: 5 Sec Memory Limit: 512 MB
Submit: 134 Solved: 51
[Submit][Status][Discuss]
Description

通往贤者之塔的路上,有许多的危机。
我们可以把这个地形看做是一颗树,根节点编号为1,目标节点编号为n,其中1-n的简单路径上,编号依次递增,
在[1,n]中,一共有n个节点。我们把编号在[1,n]的叫做正确节点,[n+1,m]的叫做错误节点。一个叶子,如果是正
确节点则为正确叶子,否则称为错误叶子。莎缇拉要帮助昴到达贤者之塔,因此现在面临着存档位置设定的问题。
为了让昴成长为英雄,因此一共只有p次存档的机会,其中1和n必须存档。被莎缇拉设置为要存档的节点称为存档
位置。当然不能让昴陷入死循环,所以存档只能在正确节点上进行,而且同一个节点不能存多次档。因为通往贤者
之塔的路上有影响的瘴气,因此莎缇拉假设昴每次位于树上一个节点时,都会等概率选择一个儿子走下去。每当走
到一个错误叶子时,再走一步就会读档。具体的,每次昴到达一个新的存档位置,存档点便会更新为这个位置(假
如现在的存档点是i,现在走到了一个存档位置j>i,那么存档点便会更新为j)。读档的意思就是回到当前存档点
。初始昴位于1,当昴走到正确节点n时,便结束了路程。莎缇拉想知道,最优情况下,昴结束路程的期望步数是多
少?
Input

第一行一个正整数T表示数据组数。
接下来每组数据,首先读入三个正整数n,m,p。
接下来m-n行,描述树上所有的非正确边(正确边即连接两个正确节点的边)
用两个正整数j,k表示j与k之间有一条连边,j和k可以均为错误节点,也可以一个为正确节点另一个为错误节点。
数据保证j是k的父亲。
50<=p<=n<=700,m<=1500,T<=5。
数据保证每个正确节点均有至少2个儿子,至多3个儿子。
Output

T行每行一个实数表示每组数据的答案。请保留四位小数。
Sample Input

1

3 7 2

1 4

2 5

3 6

3 7
Sample Output

9.0000
HINT

Source

By WerKeyTom_FTD

[Submit][Status][Discuss]


orz栋爷爷的题
题目刚放出来的那两天曾经凭借着玄学剪枝搞到了rk1
不过当时没及时发表blog,于是现在排名都没影了。。。。。
对于每一个正确节点 i ,通过树形dp预处理这两个东西
lc[i] 代表如果从 i 走到i的左儿子,从这棵子树返回存档点的期望步数
类似的也预处理 rc[i] (如果存在两个儿子的话)
那么就有一个直观的思路,定义 f[i][j] 为第 j 个存档点设在点i,期望步数
转移方程显然 f[i][j]=min{f[k][j1]+dis[k][i]}
其中 dis[i][j] 为当 ij 是两个相邻的存档点的时候,从 i 走到j的期望步数
假设现在需要计算 dis[i][j] ,那么记 xk 为从 k 走到j的期望步数
显然有 xk=13(lc[k]+xi+rc[k]+xi+xk+1)+1 (假设有两个儿子)
利用边界条件 xj=0 ,就能从最后一个式子往前代
反正用这个式子大力搞搞, O(n2) 就能统计完 dis 数组了
那么这个 dp 的原始复杂度是 O(n3) 的,还是 double 计算,似乎怎么都过不去?
但是注意到 p50n700
随便手算一下就能发现,当两个存档点距离大于 20 的时候,显然是非常不优的
那就强制每 20 个点一定要有一个存档点,这样 dp 复杂度下降为 O(20n2)
当然这个 20 应该也是可以继续往下压压的
于是就能跑得飞快啦~
好吧。。。现在这个榜。。。已经被各路神犇碾成狗了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define min(a,b) ((a) < (b) ? (a) : (b))
using namespace std;

const int G = 20;
const int maxn = 707;
const int maxm = 1505;
typedef double DB;
const DB INF = 1E18;
const DB _two = 1.00 / 2.00;
const DB _three = 1.00 / 3.00;

int n,m,p,T;
DB f[maxn][maxn],g[maxm],A[maxn],B[maxn],Dis[maxn][maxn];

vector <int> v[maxm];

inline int getint()
{
    char ch = getchar(); int ret = 0;
    while (ch < '0' || '9' < ch) ch = getchar();
    while ('0' <= ch && ch <= '9')
        ret = ret * 10 + ch - '0',ch = getchar();
    return ret;
}

inline void Dfs(int x)
{
    DB sz = 0;
    for (int i = 0; i < v[x].size(); i++)
    {
        int to = v[x][i]; Dfs(to);
        g[x] += g[to]; sz += 1.00;
    }
    if (sz > 0) g[x] /= sz; g[x] += 1.00;
}

void Solve()
{
    n = getint(); m = getint(); p = getint();
    for (int i = 2; i <= n; i++) v[i - 1].push_back(i);
    for (int i = 1; i <= m - n; i++)
    {
        int x = getint(),y = getint();
        v[x].push_back(y);
    }
    Dfs(1);
    for (int i = 1; i < n; i++)
    {
        DB sz = v[i].size();
        for (int j = 0; j < v[i].size(); j++)
        {
            int to = v[i][j];
            if (to <= n) continue;
            A[i] += 1.00; B[i] += g[to];
        }
        A[i] /= sz; B[i] /= sz; B[i] += 1.00;
    }
    for (int i = 1; i < n; i++)
    {
        DB sa = A[i],sb = B[i],tmp = 1;
        for (int j = i + 1; j <= n; j++)
        {
            Dis[i][j] = sb / (1.00 - sa);
            tmp *= v[j - 1].size() == 2 ? _two : _three;
            sa += tmp * A[j]; sb += tmp * B[j];
        }
    }
    for (int i = 2; i <= n; i++)
    {
        f[i][2] = Dis[1][i];
        for (int j = 3; j <= i; j++)
        {
            f[i][j] = INF;
            if (n - i < p - j) continue;
            for (int k = max(j - 1,i - G); k < i; k++)
                f[i][j] = min(f[i][j],f[k][j - 1] + Dis[k][i]);
        }
    }
    printf("%.4lf\n",f[n][p]);
}

void Clear()
{
    for (int i = 1; i <= n; i++)
        A[i] = B[i] = 0;
    for (int i = 1; i <= m; i++)
        g[i] = 0,v[i].clear();
}

int main()
{
    #ifdef DMC
        freopen("DMC.txt","r",stdin);
    #endif

    T = getint();
    while (T--) Solve(),Clear();
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值