题意:给定一个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;
}