zoukankan      html  css  js  c++  java
  • HDU5807分段dp

    DAG图。

    1. 【题意】 
    2. n(50)个城市m(c(n,2))条单向边(x,y),保证x<y 
    3. 对于三个点(x,y,z)如果abs(w[x]-w[y])<=K && abs(w[x]-w[y])<=K && abs(w[x]-w[y])<=K则这是一个合法状态。 
    4. 问你,如果我们从(x,y,z)出发,可以在合法状态中任意行走任意终止,有多少种不同的行走路径数 

    f[i][j][k] = ∑f[ii][jj][kk],ii,jj,kk分别为i,j,k的直接后继

    时间复杂度是O(n^6)的,需要优化。

    另开一维枚举当前要走的人。

    我们假定先走k,再走j,最后走i,目前在i,j,k。

    f[i][j][k][0]表示k,j,i走完下一轮继续走k,j,i的方案数f[u][j][k][2] += f[i][j][k][0];

    f[i][j][k][1]表示k走完下一步走j,再走i的方案数f[i][u][k][1] += f[i][j][k][2];

    f[i][j][k][2]表示k,j走完下一步走i的方案数f[i][j][u][0] += f[i][j][k][1];

    倒着dp

    1. 具体转移是这样子的—— 
    2. if (!ok(i, j) || !ok(i, k) || !ok(j, k))f[i][j][k][0] = 0; 
    3. else gadd(f[i][j][k][0], 1); 
    4.  
    5. //这个DP的起点条件并不一定是要满足ok(i,j)&&ok(i,k)&&ok(j,k),因为这个状态可能是中途状态 
    6. if (f[i][j][k][0]) 
    7.     for (int u = 1; u < i; ++u)if (e[u][i]) 
    8.         gadd(f[u][j][k][2], f[i][j][k][0]); 
    9. if(f[i][j][k][2]) 
    10.     for (int u = 1; u < j; ++u)if (e[u][j]) 
    11.     gadd(f[i][u][k][1], f[i][j][k][2]); 
    12. if(f[i][j][k][1]) 
    13.     for (int u = 1; u < k; ++u)if (e[u][k]) 
    14.     gadd(f[i][j][u][0], f[i][j][k][1]); 
    1. 【题意】 
    2. n(50)个城市m(c(n,2))条单向边(x,y),保证x<y 
    3. 对于三个点(x,y,z)如果abs(w[x]-w[y])<=K && abs(w[x]-w[y])<=K && abs(w[x]-w[y])<=K则这是一个合法状态。 
    4. 问你,如果我们从(x,y,z)出发,可以在合法状态中任意行走任意终止,有多少种不同的行走路径数 
    5.  
    6. 【类型】 
    7. 分段式DP 打破题目约束 
    8.  
    9. 【分析】 
    10. 这道题可以AC的复杂度最多只能为O(n^4) 
    11. 而一个状态是O(n^3),如果我们暴力枚举两个状态,并做转移,复杂度是O(n^6)的。 
    12. 于是我们要尝试优化—— 
    13. 我们发现,我们在转移的时候,可以考虑的不再是三重循环转移,而是分步式转移。 
    14. 即,虽然题目要求是三个人同时走,但是我们可以把其转化为三个人轮流走的情况。 
    15. 因为同时走的复杂度是是要做三种枚举。所以我们定义状态的一二三步 
    16. 即f[i][j][k][0]表示,下一步是i走 
    17. 即f[i][j][k][1]表示,下一步是j走 
    18. 即f[i][j][k][2]表示,下一步是k走 
    19. 这样答案的输出是f[i][j][k][0],这时三个人步长相同。 
    20. 因为我们计算的时候,按照基本转移方程,f[i][j][k]+=f[ii][jj][kk],(ii,jj,kk)是(i,j,k)的合法后继 
    21. 所以,(i,j,k)较大的要先算出来。于是我们倒着展开DP。 
    22.  
    23. 具体转移是这样子的—— 
    24. if (!ok(i, j) || !ok(i, k) || !ok(j, k))f[i][j][k][0] = 0; 
    25. else gadd(f[i][j][k][0], 1); 
    26.  
    27. //这个DP的起点条件并不一定是要满足ok(i,j)&&ok(i,k)&&ok(j,k),因为这个状态可能是中途状态 
    28. if (f[i][j][k][0]) 
    29.     for (int u = 1; u < i; ++u)if (e[u][i]) 
    30.         gadd(f[u][j][k][2], f[i][j][k][0]); 
    31. if(f[i][j][k][2]) 
    32.     for (int u = 1; u < j; ++u)if (e[u][j]) 
    33.     gadd(f[i][u][k][1], f[i][j][k][2]); 
    34. if(f[i][j][k][1]) 
    35.     for (int u = 1; u < k; ++u)if (e[u][k]) 
    36.     gadd(f[i][j][u][0], f[i][j][k][1]); 
    37.  
    38. 【时间复杂度&&优化】 
    39. O(n^4) 
  • 相关阅读:
    LeetCode 275. H-Index II
    LeetCode 274. H-Index
    LeetCode Gray Code
    LeetCode 260. Single Number III
    LeetCode Word Pattern
    LeetCode Nim Game
    LeetCode 128. Longest Consecutive Sequence
    LeetCode 208. Implement Trie (Prefix Tree)
    LeetCode 130. Surrounded Regions
    LeetCode 200. Number of Islands
  • 原文地址:https://www.cnblogs.com/dirge/p/5747551.html
Copyright © 2011-2022 走看看