• 【期望+状压DP】 2021 CCPC G


    Problem - G - Codeforces

    题意:

     

     

    思路:

    注意到 k 的范围是18,可以考虑状压

    要求最小的期望长度,我们可以遍历所有可能的路径,统计这些路径的期望长度的最小值即可

    那么怎么遍历呢?这里很经典的处理方式是状压DP

    设 dp[x][st] 为 当前处于 x 结点上,且经过的结点状态为 st 的最小期望路径长度

    这里的状压DP我们用记忆化搜索解决

    可能关于期望的状压DP用记忆化搜索会好处理一点(?)

    注意到在转移过程中需要用到用了哪辆车的两点之间的最短路,因此我们考虑预处理这个最短路,这个就类似于分层图的思想搞一搞就好了

    Code:

    1. #include
    2. #define int long long
    3. constexpr int N = 1e5 + 10;
    4. constexpr int Inf = 1e18;
    5. struct ty2 {
    6. int x, dis;
    7. bool operator < (const ty2 & a) const {
    8. return a.dis < dis;
    9. }
    10. };
    11. std::vectorint,int> > adj[N];
    12. std::priority_queue q;
    13. int n, m, k;
    14. int a[N];
    15. int dis[20][N], vis[N];
    16. double t, r;
    17. double dp[20][(1 << 20)], p[N];
    18. void dij(int st, int id) {
    19. for (int i = 1; i <= n; i ++) {
    20. vis[i] = 0;
    21. dis[id][i] = Inf;
    22. }
    23. dis[id][st] = 0;
    24. q.push({st, dis[id][st]});
    25. while(!q.empty()) {
    26. auto u = q.top();
    27. q.pop();
    28. if (vis[u.x]) continue;
    29. vis[u.x] = 1;
    30. for (auto [v, w] : adj[u.x]) {
    31. if (dis[id][v] > dis[id][u.x] + w) {
    32. dis[id][v] = dis[id][u.x] + w;
    33. q.push({v, dis[id][v]});
    34. }
    35. }
    36. }
    37. }
    38. double dfs(int x, int st) {
    39. if (dp[x][st]) return dp[x][st];
    40. double res = 1.0 * p[x] * dis[x][n] / t + (1.0 - p[x]) * dis[x][n] / r;
    41. for (int j = 1; j <= k; j ++) {
    42. if ((st >> (j - 1)) & 1) continue;
    43. res = std::min(res, 1.0 * (1 - p[x]) * dis[x][n] / r + p[x] * (1.0 * dis[x][a[j]] / t + dfs(j, st | (1 << (j - 1)))));
    44. }
    45. return dp[x][st] = res;
    46. }
    47. void solve() {
    48. std::cin >> t >> r >> n >> m;
    49. for (int i = 1; i <= m; i ++) {
    50. int u, v, w;
    51. std::cin >> u >> v >> w;
    52. adj[u].push_back({v, w});
    53. adj[v].push_back({u, w});
    54. }
    55. std::cin >> k;
    56. for (int i = 1; i <= k; i ++) {
    57. std::cin >> a[i] >> p[i];
    58. p[i] /= 100.0;
    59. }
    60. a[0] = 1, p[0] = 1.0;
    61. for (int i = 0; i <= k; i ++) {
    62. dij(a[i], i);
    63. }
    64. if (dis[0][n] >= Inf) {
    65. std::cout << -1 << "\n";
    66. return;
    67. }
    68. std::cout << std::fixed << std::setprecision(10) << dfs(0, 0) << "\n";
    69. }
    70. signed main() {
    71. std::ios::sync_with_stdio(false);
    72. std::cin.tie(nullptr);
    73. int t = 1;
    74. while(t --) {
    75. solve();
    76. }
    77. return 0;
    78. }

  • 相关阅读:
    关于opencv的contourArea计算方法
    Qt之Qstring
    数据结构与算法之LeetCode-515. 在每个树行中找最大值(DFS,BFS)
    用云手机运营TikTok有什么好处?
    【ARM 安全系列介绍 3.7 -- SM4 对称加密算】
    MySQL索引:作用、类型、设计原则、优化策略与常见陷阱
    完善系统的最后一公里,增加系统日志功能
    netty框架学习记录
    百货商场会员系统 加强会员身份“认同感”(上)
    Memento(备忘录模式)
  • 原文地址:https://blog.csdn.net/weixin_62528401/article/details/133191102