题目概述
有
n
个点(
ps:可以同时带上许多快递。
解题报告
刚开始以为只能带一个快递……数据范围这么小……要么DFS要么状压DP……
先想DFS,发现想要实现“可以同时带多个快递”这个功能DFS就会很慢。所以我们想状压DP。
状压怎么做?记两个状态?显然是错的。对于每个外卖有三个状态:
那么其实就是比较简单的三进制状压DP,预处理一下 3x 就行了。
示例程序
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=20,maxq=10,maxs=59049;
int n,m,q,dis[maxn+5][maxn+5],p[maxq+5];
int s[maxn+5],t[maxn+5],l[maxn+5],r[maxn+5];
int INF,f[maxn+5][maxs+5],ans;
void Floyd()
{
for (int i=1;i<=n;i++) dis[i][i]=0;
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
#define pos(x,len) ((x)/p[len]%3)
inline int Count(int x) {int tot=0;for (int i=0;i<q;i++) tot+=pos(x,i)==2;return tot;}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
scanf("%d%d%d",&n,&m,&q);memset(dis,63,sizeof(dis));
for (int i=1,x,y,z;i<=m;i++) scanf("%d%d%d",&x,&y,&z),dis[x][y]=min(dis[x][y],z);
for (int i=0;i<q;i++) scanf("%d%d%d%d",&s[i],&t[i],&l[i],&r[i]);
Floyd();p[0]=1;for (int i=1;i<=q;i++) p[i]=p[i-1]*3;
memset(f,63,sizeof(f));INF=f[0][0];f[1][0]=0;
for (int j=1;j<p[q];j++)
for (int i=0;i<q;i++)
if (pos(j,i)==1)
{
for (int k=1;k<=n;k++) if (f[k][j-p[i]]<INF&&f[k][j-p[i]]+dis[k][s[i]]<=r[i])
f[s[i]][j]=max(l[i],min(f[s[i]][j],f[k][j-p[i]]+dis[k][s[i]]));
} else
if (pos(j,i)==2)
{
for (int k=1;k<=n;k++) if (f[k][j-p[i]]<INF&&f[k][j-p[i]]+dis[k][t[i]]<=r[i])
f[t[i]][j]=min(f[t[i]][j],f[k][j-p[i]]+dis[k][t[i]]);
}
for (int j=0;j<p[q];j++)
for (int i=1;i<=n;i++)
if (f[i][j]<INF) ans=max(ans,Count(j));
return printf("%d\n",ans),0;
}