hdu5807Keep In Touch

探讨了一个关于50个点的有向无环图(DAG)的问题,目标是在给定条件限制下,计算三个特工在图中移动的所有可能路径数量。采用动态规划方法进行高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5807

题意:给定一个50个点的DAG图每个点有个权值w[i],给定初始3个特工所在的位置是x,y,z这3个城市,每一时刻每个人都得移动到下一个城市,并且要求每一时刻两两之间都能联系但且仅当任意两个城市之间的权值差<=k,求有多少种方案结束任务。

分析:因为是DAG图我们可以很容易想到设状态[i][j][k]表示当3个人恰好分别在i和j和k时的方案数,然后要处理的就是如果将后继状态的方案也统计到当前状态啦。如果我们直接去枚举3个位置的后继状态的话这样会是n^3总的时间复杂度就会是O(n^6),这样在完全图时是会T的。我们考虑将这3个人分开移动,设dp[0][i][j][k]表示这个时刻3个人恰好在i和j和k,设dp[1][i][j][k]表示当前时刻第二个人在j而第一个人和第三个人还在上一时刻的地点i和k,设dp[2][i][j][k]表示当前时刻第二个人在j和第三个人在k而第一个人还在上一时刻的地点i。这样的话我们就能从dp[0]->dp[1],dp[1]->dp[2],dp[2]->dp[0]。详见代码。O(n^4)

代码:

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<vector>
#include<string>
#include<stdio.h>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=55;
const int mod=998244353;
const int MOD1=1000000007;
const int MOD2=1000000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000007;
const int INF=1000000010;
const ll MAX=1ll<<55;
const double pi=acos(-1.0);
typedef double db;
typedef unsigned long long ull;
int w[N],ma[N][N],dp[3][N][N][N];
int ABS(int a,int b,int c) {
    return max(abs(a-b),max(abs(b-c),abs(a-c)));
}
int main()
{
    int a,b,c,i,j,k,h,n,m,lim,q,t;
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d%d%d", &n, &m, &lim, &q);
        for (i=1;i<=n;i++) scanf("%d", &w[i]);
        memset(ma,0,sizeof(ma));
        for (i=1;i<=m;i++) scanf("%d%d", &a, &b),ma[b][a]=1;
        for (i=n;i;i--)
            for (j=n;j;j--)
                for (k=n;k;k--) {
                    dp[0][i][j][k]=1;dp[1][i][j][k]=dp[2][i][j][k]=0;
                    for (h=i+1;h<=n;h++) if (ma[h][i]) (dp[0][i][j][k]+=dp[2][h][j][k])%=mod;
                    for (h=j+1;h<=n;h++) if (ma[h][j]) (dp[1][i][j][k]+=dp[0][i][h][k])%=mod;
                    for (h=k+1;h<=n;h++) if (ma[h][k]) (dp[2][i][j][k]+=dp[1][i][j][h])%=mod;
                    if (ABS(w[i],w[j],w[k])>lim) dp[0][i][j][k]=0;
                }
        while (q--) {
            scanf("%d%d%d", &a, &b, &c);
            printf("%d\n", dp[0][a][b][c]);
        }
    }
    return 0;
}


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值