[HDU5807] [BestCoder Round #86 1004] Keep In Touch (DP)

Posted birchtree

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HDU5807] [BestCoder Round #86 1004] Keep In Touch (DP)相关的知识,希望对你有一定的参考价值。

[HDU5807] [BestCoder Round #86 1004] Keep In Touch (DP)

题面

有三个人从一张N个点无重边的有向无环图上的三个点出发,每单位时间,他们分别选择当前点的一条出边走下去。有向无环图点有点权,任意时刻他们所在的三个点两两点权相差不超过K。他们可以在任意三个点同时结束。求合法的路径总数。N≤50。

分析

暴力的做法,设\(dp[i][j][k]\)表示第一个人在i,第二个人在j,第三个人在k的方案数,然后枚举三个人接着到的地方x,y,z,倒推\(dp[i][j][k]=\sum dp[x][y][z]\)。这样的时间复杂度是\(O(n^6)\)

注意到我们没必要每次让三个人一起走,只要分三次走就可以了。给dp再加一维,\(dp[i][j][k][0/1/2]\)分别表示轮到第1个人走(初始状态),第2个人走,第3个人走。然后由2转移到0,0转移到1,1转移到2即可。这样的时间复杂度是\(O(n^4)\)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 50
#define mod 998244353 
using namespace std;
int t,n,lim,m,q;
int w[maxn+5];
int g[maxn+5][maxn+5];
int dp[maxn+5][maxn+5][maxn+5][3];
void ini()
    memset(g,0,sizeof(g));
    memset(dp,0,sizeof(dp));

int main()
    int u,v,a,b,c;
    scanf("%d",&t);
    for(int cas=1;cas<=t;cas++)
        ini();
        scanf("%d %d %d %d",&n,&m,&lim,&q);
        for(int i=1;i<=n;i++) scanf("%d",&w[i]); 
        for(int i=1;i<=m;i++)
            scanf("%d %d",&u,&v);
            g[u][v]=1;
        
        for(int i=n;i>=1;i--)//题目要求u<v,所以倒推 
            for(int j=n;j>=1;j--)
                for(int k=n;k>=1;k--)
                    dp[i][j][k][0]=1;
                    dp[i][j][k][1]=0;
                    dp[i][j][k][2]=0;
                    for(int u=i+1;u<=n;u++)
                        if(g[i][u])
                            dp[i][j][k][0]+=dp[u][j][k][2];
                            dp[i][j][k][0]%=mod;
                        
                    
                    for(int u=j+1;u<=n;u++)
                        if(g[j][u])
                            dp[i][j][k][1]+=dp[i][u][k][0];
                            dp[i][j][k][1]%=mod;
                        
                    
                    for(int u=k+1;u<=n;u++)
                        if(g[k][u])
                            dp[i][j][k][2]+=dp[i][j][u][1];
                            dp[i][j][k][2]%=mod;
                        
                    
                    if(max(max(abs(w[i]-w[j]),abs(w[i]-w[k])),abs(w[j]-w[k]))>lim) dp[i][j][k][0]=0;
                 
             
        
        for(int i=1;i<=q;i++)
            scanf("%d %d %d",&a,&b,&c);
            printf("%d\n",dp[a][b][c][0]);
        
     

以上是关于[HDU5807] [BestCoder Round #86 1004] Keep In Touch (DP)的主要内容,如果未能解决你的问题,请参考以下文章

hdu4908 &amp; BestCoder Round #3 BestCoder Sequence(组合数学)

BestCoder Round #77 (div.2)(hdu5650,hdu5651(逆元),hdu5652(二分),hdu5653(dp))

BestCoder Round #69 (div.2)(hdu5611)

BestCoder Round #66 (div.2) hdu5592

BestCoder Round #73 (div.2)(hdu 5630)

Hdu BestCoder 开分矿