Luogu P2081 [NOI2012]迷失游乐园 | 期望 DP 基环树

题目链接

基环树套路题。(然而各种错误调了好久233)

当$m=n-1$时,原图是一棵树。

先以任意点为根做$dp$,求出从每一个点出发,然后只往自己子树里走时路径的期望长度。

接着再把整棵树再扫一遍,求出从每一个点出发时路径的期望长度。

最后再统计一遍答案即可。

当$m=n$时,原图是一棵基环树。

先找到图中那唯一的一个环,然后以环上的每一个节点为根在此节点的子树内做$dp$。

环上节点的数量很少,$dp$之后直接暴力算出从每一个环上节点出发时路径的期望长度。

然后把每一个环上节点的子树扫一遍,求出从每一个点出发时路径的期望长度。

最后再统计一遍答案即可。

#include<iostream>
#include<cstdio>
#include<fstream>
    using namespace std;
struct edge
{
    int last;
    int end;
    int weight;
}e[200005];
    int n=0,m=0,root=0;
    int ne=1,cnt[100005],note[100005];
    int tot=0,ring[100005];
    int ringdis[100005];
    bool flag=false,vis[100005],inring[100005];
    double ans=0,f[100005],d[100005];
void NewEdge(int u,int v,int w)
{
    ne++;
    e[ne].last=note[u];
    e[ne].end=v;
    e[ne].weight=w;
    note[u]=ne;
}
void dfs(int x,int fx)
{
    cnt[x]=f[x]=0;
    for(int i=note[x];i;i=e[i].last)
    {
        if(e[i].end==fx||inring[e[i].end]) continue;
        dfs(e[i].end,x),cnt[x]++;
    }
    if(cnt[x]==0) return;
    for(int i=note[x];i;i=e[i].last)
    {
        if(e[i].end==fx||inring[e[i].end]) continue;
        f[x]+=e[i].weight+f[e[i].end];
    }
    f[x]/=cnt[x];
}
void dfss(int x,int fx,int w)
{
    if(x==root&&!inring[x]) d[x]=f[x];
    else if(x!=root)
    {
        d[x]=f[x]*cnt[x]/(cnt[x]+1);
        if(fx==root&&cnt[fx]==1) d[x]+=(double)w/(cnt[x]+1);
        else if(fx==root) d[x]+=((d[fx]*cnt[fx]-f[x]-w)/(cnt[fx]-1)+w)/(cnt[x]+1);
        else d[x]+=((d[fx]*(cnt[fx]+1)-f[x]-w)/cnt[fx]+w)/(cnt[x]+1);
    }
    for(int i=note[x];i;i=e[i].last)
    {
        if(e[i].end==fx||inring[e[i].end]) continue;
        dfss(e[i].end,x,e[i].weight);
    }
}
void dfsss(int x,int fe)
{
    if(flag) return;
    vis[x]=true,ring[++tot]=x;
    for(int i=note[x];i;i=e[i].last)
    {
        if(i==(fe^1)) continue;
        if(flag) break;
        if(vis[e[i].end])
        {
            int st=0,ed=tot,h=e[i].end;
            for(int i=1;i<=tot;i++)
                if(ring[i]==h) {st=i;break;}
            for(int i=st;i<=ed;i++)
            {
                inring[ring[i]]=true;
                for(int j=note[ring[i]];j;j=e[j].last)
                    if(e[j].end==((i==ed)?ring[st]:ring[i+1]))
                        {ringdis[i]=e[j].weight;break;}
            }
            for(int i=st;i<=ed;i++) dfs(ring[i],0);
             for(int i=st;i<=ed;i++)
            {
                int x=ring[i];
                d[x]=f[x]*cnt[x]/(cnt[x]+2);
                int u=i,w=0;
                double p=1;
                for(;;)
                {
                    p/=cnt[ring[u]]+((u==i)?2:1),w=ringdis[u];
                    u=((u+1>ed)?st:(u+1));
                    if(((u+1>ed)?st:(u+1))==i) 
                        {d[x]+=p*(f[ring[u]]+w); break;}
                    else d[x]+=p*(f[ring[u]]*cnt[ring[u]]/(cnt[ring[u]]+1)+w);
                }
                u=i,w=0,p=1;
                for(;;)
                {
                    p/=cnt[ring[u]]+((u==i)?2:1),w=ringdis[(u-1<st)?ed:(u-1)];
                    u=((u-1<st)?ed:(u-1));
                    if(((u-1<st)?ed:(u-1))==i) 
                        {d[x]+=p*(f[ring[u]]+w); break;}
                    else d[x]+=p*(f[ring[u]]*cnt[ring[u]]/(cnt[ring[u]]+1)+w);
                }
            }
            for(int i=st;i<=ed;i++)
                cnt[ring[i]]+=2,root=ring[i],dfss(root,0,0);
            flag=true; break;
        }
        dfsss(e[i].end,i);
    }
    tot--;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int u=0,v=0,w=0;
        scanf("%d%d%d",&u,&v,&w);
        NewEdge(u,v,w);
        NewEdge(v,u,w);
    }
    if(m==n-1) root=1,dfs(root,0),dfss(root,0,0);
          else dfsss(1,0);
    for(int i=1;i<=n;i++)
        ans+=(double)1/n*d[i];
    printf("%.5f",ans);
    return 0;
}
Luogu P2081

 

转载于:https://www.cnblogs.com/wozaixuexi/p/11216153.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的体育馆管理系统,源码+数据库+毕业论文+视频演示 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本体育馆管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达到事半功倍的效果。此体育馆管理系统利用当下成熟完善的SpringBoot框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的Mysql数据库进行程序开发。实现了用户在线选择试题并完成答题,在线查看考核分数。管理员管理收货地址管理、购物车管理、场地管理、场地订单管理、字典管理、赛事管理、赛事收藏管理、赛事评价管理、赛事订单管理、商品管理、商品收藏管理、商品评价管理、商品订单管理、用户管理、管理员管理等功能。体育馆管理系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。 关键词:体育馆管理系统;SpringBoot框架;Mysql;自动化
P2375 [NOI2014] 动物园是一道经典的动态规划题目,以下是该题的详细题意和解题思路。 【题意描述】 有两个长度为 $n$ 的整数序列 $a$ 和 $b$,你需要从这两个序列中各选出一些数,使得这些数构成一个新的序列 $c$。其中,$c$ 序列中的元素必须在原序列中严格递增。每个元素都有一个价值,你的任务是选出的元素的总价值最大。 【解题思路】 这是一道经典的动态规划题目,可以采用记忆化搜索的方法解决,也可以采用递推的方法解决。 记忆化搜索的代码如下: ```c++ #include <iostream> #include <cstdio> #include <cstring> using namespace std; const int MAXN = 1005; int dp[MAXN][MAXN], a[MAXN], b[MAXN], n; int dfs(int x, int y) { if (dp[x][y] != -1) return dp[x][y]; if (x == n || y == n) return 0; int res = max(dfs(x + 1, y), dfs(x + 1, y + 1)); if (a[x] > b[y]) { res = max(res, dfs(x, y + 1) + b[y]); } return dp[x][y] = res; } int main() { scanf("%d", &n); for (int i = 0; i < n; i++) scanf("%d", &a[i]); for (int i = 0; i < n; i++) scanf("%d", &b[i]); memset(dp, -1, sizeof(dp)); printf("%d\n", dfs(0, 0)); return 0; } ``` 其中,dp[i][j]表示选到a数组中第i个元素和b数组中第j个元素时的最大价值,-1表示未计算过。dfs(x,y)表示选到a数组中第x个元素和b数组中第y个元素时的最大价值,如果dp[x][y]已经计算过,则直接返回dp[x][y]的值。如果x==n或者y==n,表示已经遍历完一个数组,直接返回0。然后就是状态转移方程了,如果a[x] > b[y],则可以尝试选b[y],递归调用dfs(x, y+1)计算以后的最大价值。否则,只能继续遍历数组a,递归调用dfs(x+1, y)计算最大价值。最后,返回dp[0][0]的值即可。 递推的代码如下: ```c++ #include <iostream> #include <cstdio> #include <cstring> using namespace std; const int MAXN = 1005; int dp[MAXN][MAXN], a[MAXN], b[MAXN], n; int main() { scanf("%d", &n); for (int i = 0; i < n; i++) scanf("%d", &a[i]); for (int i = 0; i < n; i++) scanf("%d", &b[i]); for (int i = n - 1; i >= 0; i--) { for (int j = n - 1; j >= 0; j--) { dp[i][j] = max(dp[i + 1][j], dp[i + 1][j + 1]); if (a[i] > b[j]) { dp[i][j] = max(dp[i][j], dp[i][j + 1] + b[j]); } } } printf("%d\n", dp[0][0]); return 0; } ``` 其中,dp[i][j]表示选到a数组中第i个元素和b数组中第j个元素时的最大价值。从后往前遍历数组a和数组b,依次计算dp[i][j]的值。状态转移方程和记忆化搜索的方法是一样的。 【参考链接】 P2375 [NOI2014] 动物园:https://www.luogu.com.cn/problem/P2375
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值