zoukankan      html  css  js  c++  java
  • Luogu P1730 最小密度路径(最短路径+dp)

    P1730 最小密度路径

    题面

    题目描述

    给出一张有 (N) 个点 (M) 条边的加权有向无环图,接下来有 (Q) 个询问,每个询问包括 (2) 个节点 (X)(Y) ,要求算出从 (X)(Y) 的一条路径,使得密度最小(密度的定义为,路径上边的权值和除以边的数量)。

    输入输出格式

    输入格式:

    第一行包括 (2) 个整数 (N)(M)

    以下 (M) 行,每行三个数字 (A)(B)(W) ,表示从 (A)(B) 有一条权值为 (W) 的有向边。

    再下一行有一个整数 (Q)

    以下 (Q) 行,每行一个询问 (X)(Y) ,如题意所诉。

    输出格式:

    对于每个询问输出一行,表示该询问的最小密度路径的密度(保留 (3) 位小数),如果不存在这么一条路径输出“OMG!”(不含引号)。

    输入输出样例

    输入样例:

    3 3
    1 3 5
    2 1 6
    2 3 6
    2
    1 3
    2 3
    

    输出样例:

    5.000
    5.500
    

    说明

    (1 leq N leq 50, 1 leq M leq 1000, 1 leq W leq 100000, 1 leq Q leq 100000)

    思路

    我们来做一点 (NOIP D1T2) 难度的图论题吧......来,洛谷 P4467。 --digger_sun

    下午孙教练突然叫我们过去做了一些图论题,太毒瘤了 (qwq) 。特别是这道题,我没有做出来,因为完全没和动态规划联系到一起。最后则是 logeadd 的代码救了我。

    进入正题。显然普通的松弛操作在这里不适用了,考虑使用记录状态的动态规划。定义 (dis[i][j][k]) 为从 (i) 点出发到达 (j) 点,中途恰好经过了 (k) 条边的最短距离。那么假设在从点 (s) 出发的一次最短路中,现在的状态是已经经过了 (k) 条边的点 (u) 和它的最短路径,对于一条边 ((u,v,d)) 我们就可以这样松弛:

    [f[s][v][k+1]=min(f[s][v][k+1],f[u][v][k]+d) ]

    最后统计答案时枚举经过的边数,就可以完成啦。

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<int,int> PII;
    const int INF=0x3f3f3f3f;
    int n,m,q,dis[55][55][1005];
    int cnt,top[55],to[1005],len[1005],nex[1005];
    int read()
    {
        int re=0;
        char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
        return re;
    }
    void SPFA(int s)
    {
        dis[s][s][0]=0;
        queue<PII>Q;
        Q.push(make_pair(s,0));
        while(!Q.empty())
        {
            int now=Q.front().first,edge=Q.front().second;Q.pop();
            for(int i=top[now];i;i=nex[i])
                if(dis[s][to[i]][edge+1]>dis[s][now][edge]+len[i])
                {
                    dis[s][to[i]][edge+1]=dis[s][now][edge]+len[i];
                    Q.push(make_pair(to[i],edge+1));
                }
        }
        return ;
    }
    int main()
    {
        n=read(),m=read();
        memset(dis,0x3f,sizeof dis);
        for(int i=0;i<m;i++)
        {
            int x=read(),y=read(),z=read();
            to[++cnt]=y,len[cnt]=z,nex[cnt]=top[x],top[x]=cnt;
        }
        q=read();
        while(q--)
        {
            int s=read(),t=read();
            SPFA(s);
            double ans=INF;
            for(int i=1;i<=m;i++) if(dis[s][t][i]!=INF) ans=min(ans,double(dis[s][t][i])/double(i));
            if(ans!=INF) printf("%.3f
    ",ans);
            else puts("OMG!");
        }
        return 0;
    }
    
    
  • 相关阅读:
    C/C++中的内存对齐 C/C++中的内存对齐
    Java编程提高性能时需注意的地方
    微软HoloLens技术解谜
    MySQL索引原理及慢查询优化
    mysql 2006
    第9周个人总结
    第十周任务安排
    下一阶段学习安排
    写在软考弃考之后
    第九周任务安排
  • 原文地址:https://www.cnblogs.com/coder-Uranus/p/9724670.html
Copyright © 2011-2022 走看看