zoukankan      html  css  js  c++  java
  • bzoj 1415 [Noi2005]聪聪和可可——其实无环的图上概率

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1415

    乍一看和“游走”一样。于是高斯消元。n^2状态,复杂度n^6……

    看看TJ,发现因为聪聪不是随便走的,所以聪聪一直逼近可可。故其实无环。可以记搜。

    (1A还是不错的)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int N=1005;
    int n,m,l0,l1,nxt[N][N],dfn[N],du[N];
    double dp[N][N];
    bool vis[N],vs[N][N];
    priority_queue<int,vector<int>,greater<int> >ed[N];
    void add(int x,int y)
    {
        ed[x].push(y);ed[y].push(x);
        du[x]++;du[y]++;
    }
    void bfs(int cr)
    {
        priority_queue<int,vector<int>,greater<int> >tp;
        memset(vis,0,sizeof vis);memset(dfn,0,sizeof dfn);
        queue<int> q;q.push(cr);vis[cr]=1;nxt[cr][cr]=cr;
        while(q.size())
        {
            int k=q.front();q.pop();
            tp=ed[k];
            while(tp.size())
            {
                int v=tp.top();tp.pop();
                if(vis[v])continue;
                dfn[v]=dfn[k]+1;vis[v]=1;q.push(v);
                if(dfn[v]>2)nxt[v][cr]=nxt[k][cr];
                else nxt[v][cr]=v;
            }
        }
    }
    double dfs(int x,int y)//coco->x ,cncn->y
    {
    //    printf("x=%d y=%d
    ",x,y);
        if(vs[x][y])return dp[x][y];vs[x][y]=1;
        if(nxt[x][y]==x){/*printf("rt x=%d y=%d
    ",x,y);*/return dp[x][y]=1;}
        double ret=(dfs(x,nxt[x][y])+(nxt[x][y]!=x))/(du[x]+1);
        priority_queue<int,vector<int>,greater<int> >tp=ed[x];//每层定义 
    //    printf("siz[%d]=%d
    ",x,tp.size());
        while(tp.size())
        {
            int v=tp.top();tp.pop();
    //        printf("v=%d nxt[%d][%d]=%d
    ",v,x,y,nxt[x][y]);
            ret+=(dfs(v,nxt[x][y])+(nxt[x][y]!=v))/(du[x]+1);
        }
    //    printf("ret=%.3lf
    ",ret);
        return dp[x][y]=ret;
    }
    int main()
    {
        scanf("%d%d%d%d",&n,&m,&l0,&l1);int x,y;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);add(x,y);
        }
        for(int i=1;i<=n;i++)bfs(i);
        printf("%.3lf",dfs(l1,l0));
        return 0;
    }
    版本1

    看看TJ,发现判断得那么纠结是因为x==y时正常应返回0。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int N=1005;
    int n,m,l0,l1,nxt[N][N],dfn[N],du[N];
    double dp[N][N];
    bool vis[N],vs[N][N];
    priority_queue<int,vector<int>,greater<int> >ed[N];
    void add(int x,int y)
    {
        ed[x].push(y);ed[y].push(x);
        du[x]++;du[y]++;
    }
    void bfs(int cr)
    {
        priority_queue<int,vector<int>,greater<int> >tp;
        memset(vis,0,sizeof vis);memset(dfn,0,sizeof dfn);
        queue<int> q;q.push(cr);vis[cr]=1;nxt[cr][cr]=cr;
        while(q.size())
        {
            int k=q.front();q.pop();
            tp=ed[k];
            while(tp.size())
            {
                int v=tp.top();tp.pop();
                if(vis[v])continue;
                dfn[v]=dfn[k]+1;vis[v]=1;q.push(v);
                if(dfn[v]>2)nxt[v][cr]=nxt[k][cr];
                else nxt[v][cr]=v;
            }
        }
    }
    double dfs(int x,int y)//coco->x ,cncn->y
    {
        if(vs[x][y])return dp[x][y];vs[x][y]=1;
        if(x==y)return dp[x][y]=0;//
        if(nxt[x][y]==x)return dp[x][y]=1;
        double ret=dfs(x,nxt[x][y])/(du[x]+1)+1;
        priority_queue<int,vector<int>,greater<int> >tp=ed[x];//每层定义 
        while(tp.size())
        {
            int v=tp.top();tp.pop();
            ret+=dfs(v,nxt[x][y])/(du[x]+1);
        }
        return dp[x][y]=ret;
    }
    int main()
    {
        scanf("%d%d%d%d",&n,&m,&l0,&l1);int x,y;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);add(x,y);
        }
        for(int i=1;i<=n;i++)bfs(i);
        printf("%.3lf",dfs(l1,l0));
        return 0;
    }
    版本2

    但是自己代码巨慢……想来是用了优先队列的缘故(为了标号字典序)。尝试改一改。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int N=1005;
    int n,m,l0,l1,nxt[N][N],dfn[N],du[N],head[N],xnt;
    double dp[N][N];
    bool vis[N],vs[N][N];
    priority_queue<int,vector<int>,greater<int> >ed[N];
    struct Edge{
        int next,to;
        Edge(int n=0,int t=0):next(n),to(t) {}
    }edge[N<<1];
    void add(int x,int y)
    {
        edge[++xnt]=Edge(head[x],y);head[x]=xnt;
        edge[++xnt]=Edge(head[y],x);head[y]=xnt;
        ed[x].push(y);ed[y].push(x);
        du[x]++;du[y]++;
    }
    void bfs(int cr)
    {
        priority_queue<int,vector<int>,greater<int> >tp;
        memset(vis,0,sizeof vis);memset(dfn,0,sizeof dfn);
        queue<int> q;q.push(cr);vis[cr]=1;nxt[cr][cr]=cr;
        while(q.size())
        {
            int k=q.front();q.pop();
            tp=ed[k];
            while(tp.size())
            {
                int v=tp.top();tp.pop();
                if(vis[v])continue;
                dfn[v]=dfn[k]+1;vis[v]=1;q.push(v);
                if(dfn[v]>2)nxt[v][cr]=nxt[k][cr];
                else nxt[v][cr]=v;
            }
        }
    }
    double dfs(int x,int y)//coco->x ,cncn->y
    {
        if(vs[x][y])return dp[x][y];vs[x][y]=1;
        if(x==y)return dp[x][y]=0;//
        if(nxt[x][y]==x)return dp[x][y]=1;
        double ret=dfs(x,nxt[x][y])/(du[x]+1)+1;
        for(int i=head[x];i;i=edge[i].next)
            ret+=dfs(edge[i].to,nxt[x][y])/(du[x]+1);
        return dp[x][y]=ret;
    }
    int main()
    {
        scanf("%d%d%d%d",&n,&m,&l0,&l1);int x,y;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);add(x,y);
        }
        for(int i=1;i<=n;i++)bfs(i);
        printf("%.3lf",dfs(l1,l0));
        return 0;
    }

    结果只是快了28ms。

    别人用一些方法保证字典序。

    这个人bfs+两步保证dis最小的前提下调整标号至最小。https://blog.csdn.net/clove_unique/article/details/62237321

    这个人spfa的同时判断标号。(但只能记录一步的pre)https://blog.csdn.net/PoPoQQQ/article/details/40896403(bfs因为是bfs所以不能边求dis边调整标号)

    可是我都没记录dis。用的dfn。所以懒得改了……比较欣赏第一个人的写法。

  • 相关阅读:
    什么样的代码称得上是好代码?
    九年程序人生 总结分享
    Docker入门 第一课 --.Net Core 使用Docker全程记录
    阿里云 Windows Server 2012 r2 部署asp.net mvc网站 平坑之旅
    Visual studio 2015 Community 安装过程中遇到问题的终极解决
    Activiti6.0 spring5 工作流引擎 java SSM流程审批 项目框架
    java 进销存 库存管理 销售报表 商户管理 springmvc SSM crm 项目
    Leetcode名企之路
    24. 两两交换链表中的节点
    21. 合并两个有序链表
  • 原文地址:https://www.cnblogs.com/Narh/p/9206642.html
Copyright © 2011-2022 走看看