题面
分析
刚看到这道题时想的是跟最短哈密顿路类似的二进制状压DP,先用floyd处理距离
但是此题用二进制不够,应该用三进制
0,1,2分别表示未送,正在送,已送完
dp[s][i]表示当前送到任务状态为s,现在在点i
状态转移方程见代码
时间复杂度(O(n^3+3^qqn)
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxs 60000
#define maxn 22
#define INF 0x3f3f3f3f
using namespace std;
int n,m,q;
int pow3[maxs];
int dp[maxs][maxn];
int dist[maxn][maxn];
int s[maxn];
int t[maxn];
int l[maxn];
int r[maxn];
void floyd(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);
}
}
}
}
int main(){
int u,v,w;
scanf("%d %d %d",&n,&m,&q);
memset(dist,0x3f,sizeof(dist));
for(int i=1;i<=m;i++){
scanf("%d %d %d",&u,&v,&w);
dist[u][v]=min(dist[u][v],w);
}
for(int i=1;i<=n;i++) dist[i][i]=0;
floyd();
for(int i=1;i<=q;i++){
scanf("%d %d %d %d",&s[i],&t[i],&l[i],&r[i]);
}
pow3[0]=1;
for(int i=1;i<=q;i++){
pow3[i]=pow3[i-1]*3;
}
memset(dp,0x3f,sizeof(dp));
dp[0][1]=0;
int ans=0,cnt=0;
for(int i=0;i<pow3[q];i++){//状态
for(int j=1;j<=n;j++){//当前位置
if(dp[i][j]==INF) continue;
cnt=0;
for(int k=1;k<=q;k++){
int digit=(i/pow3[k-1])%3;
if(digit==0){//开始送一个快递k,从当前位置j到第k个任务的起点s[k],i的第k位由0变1
//和l[k]取min是处理到的太早,要等到l[k]时刻才能领到货物
dp[i+pow3[k-1]][s[k]]=min(dp[i+pow3[k-1]][s[k]],max(dp[i][j]+dist[j][s[k]],l[k]));
}else if(digit==1){//送完快递k,从当前位置j到第k个任务的结束点t[k],i的第k位由1变2
//注意判断dp[i][j]+dist[j][t[k]]<=r[k],因为必须要在r[k]时刻前送完货物
if(dp[i][j]+dist[j][t[k]]<=r[k]) dp[i+pow3[k-1]][t[k]]=min(dp[i+pow3[k-1]][t[k]],dp[i][j]+dist[j][t[k]]);
}else cnt++;
}
ans=max(ans,cnt);
}
}
printf("%d
",ans);
}