牛客 补题 瘦了的牛牛去旅游 图 dp

    技术2022-07-11  89

    瘦了的牛牛去旅游

    题目链接

    题目大意

    给一个有向图, 有边权。一个路径的密度 = 这条路上的边权和 / 这条路上边的数量。有q次询问 ,每次询问 给两个点,问这两个点路径上的密度最小是多少。 数据范围:点的数量n(50)边的数量m(1000)询问的数量q(1e5)

    题解

    我做的时候比较捞。。一直没想到dp这种东西。。一看见图就一直在想怎么建图跑个什么东西。。还是菜啊 dp[i][j][k] 表示i到j经过k个边的最小路径长度。 状态转移就很简单了,找一个中间点,然后转移。。。 肯定要先枚举k因为转移k要用到k - 1. 代码:

    #include <algorithm> #include <cstdio> #include <iostream> #include <vector> #include <stack> #include <queue> #include <map> #include <cmath> #include <set> #include <cstring> #include <string> #include <bitset> #include <stdlib.h> #include <time.h> using namespace std; typedef long long ll; typedef pair<int,int> pii; typedef unsigned long long ull; #define st first #define sd second #define mkp make_pair #define pb push_back void wenjian(){freopen("concatenation.in","r",stdin);freopen("concatenation.out","w",stdout);} void tempwj(){freopen("hash.in","r",stdin);freopen("hash.out","w",stdout);} ll gcd(ll a,ll b){return b == 0 ? a : gcd(b,a % b);} ll qpow(ll a,ll b,ll mod){a %= mod;ll ans = 1;while(b){if(b & 1)ans = ans * a % mod;a = a * a % mod;b >>= 1;}return ans;} struct cmp{bool operator()(const pii & a, const pii & b){return a.second > b.second;}}; int lb(int x){return x & -x;} const int inf = 0x3f3f3f3f; const ll INF = 0x3f3f3f3f3f3f3f3f; const ll mod = 998244353; const int maxn = 100+5; int dis[maxn][maxn]; int dp[maxn][maxn][maxn]; double ans[maxn][maxn]; int main() { int n,m; scanf("%d%d",&n,&m); for (int i = 1; i <= n; i ++ ) { for (int j = 1; j <= n; j ++ ) { dis[i][j] = inf; } } for (int i = 1; i <= n; i ++ ) { for (int j = 1; j <= n; j ++ ) { for (int k = 0; k <= n; k ++ ) dp[i][j][k] = inf; } } for (int i = 1; i<= m; i ++ ) { int x,y,v; scanf("%d%d%d",&x,&y,&v); dis[x][y] = min(dis[x][y],v); } for (int i= 1; i <= n; i ++ ) dp[i][i][0] = 0; for (int k = 1; k <= n; k ++ ) { for (int i =1; i <= n; i ++ ) // i -> j 过k个边的最小路径长度 { for (int j = 1; j<= n; j ++ ) { for (int p = 1; p <= n; p ++ ) { dp[i][j][k] = min(dp[i][j][k],dp[i][p][k - 1] + dis[p][j]); } } } } // for (int i = 1; i <= n; i ++ ) // { // for (int j = 1; j <= n; j ++ ) // { // printf("%d %d\n",i,j); // for(int k= 1; k <= n; k ++ ) // { // printf("%d ",dp[i][j][k]); // } // printf("\n"); // } // } for (int i = 1; i <= n; i ++ ) { for (int j = 1; j <= n; j ++ ) { if(i == j) { ans[i][j] = 0; continue; } double s = inf; ans[i][j] = inf; for (int k = 1; k <= n; k ++ ) { if(dp[i][j][k] == inf) continue; s = min(s,1.0 * dp[i][j][k]/k); } ans[i][j] = s; } } int q; scanf("%d",&q); while(q -- ) { int x,y; scanf("%d%d",&x,&y); if(ans[x][y] == inf) printf("OMG!\n"); else printf("%.3f\n",ans[x][y]); } }
    Processed: 0.015, SQL: 9