AT_kupc2013_f 7歳教 题解
O(N^3)
既然题目对所经过的城市没有要求,所以可以跑一遍最短路。考虑到城市数量较少,使用
Floyd算法
,时间复杂度为
小结论:在一个城市要么路过,要么一直待到该城市的加分时间截止。
如果我来到这个城市的时间在加分时间段之后,那么我必然去别的城市。(路过)
如果我现在在这个城市时可以加分,那我为什么要去别的地方呢,因为每天不论在哪个城市加的分是一样的。(就像一个人有两个地方可以打零工,他现在在一处上班,肯定不会再花时间去另一个地方,不光路上要花时间,到那边开不开门也另说)
考虑到这个结论,我们除去路过的城市,肯定是先去截止时间早的城市加分,再去截止时间晚的城市加分。
所以我们可以按照截止时间排序,在考虑从截止时间早的城市走来就行了,时间复杂度为
#include<iostream>
#include<algorithm>
using namespace std;
struct node
{
long long l,r,id;
};
node a[503];
long long v[503][503];
long long f[503];//表示目前到 i 这个节点的最大积分
long long n,st,ti,maxx,from,to,maxxxx=1ll<<60;
bool cmp(node x,node y)
{
return x.r<y.r;
}
int main()
{
scanf("%lld%lld",&n,&st);
for(int i=1;i<=n;i++) scanf("%lld%lld",&a[i].l,&a[i].r),a[i].id=i,f[i]=-maxxxx;//初始化
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%lld",&v[i][j]);
for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) v[i][j]=min(v[i][k]+v[k][j],v[i][j]);//Floyd
sort(a+1,a+1+n,cmp);
f[st]=0;
for(int i=1;i<=n;i++)
{
to=a[i].id;//截止时间晚的城市
for(int j=1;j<i;j++)
{
from=a[j].id;//截止时间早的城市
ti=max(a[j].r+v[from][to],a[i].l);//从到达这一城市或这一城市开始时间算
if(a[i].r>=ti) f[to]=max(f[to],f[from]+a[i].r-ti);//状态转移
}
ti=max(v[st][to],a[i].l);//从起点走来
if(a[i].r>=ti) f[to]=max(f[to],a[i].r-ti);//状态转移
}
for(int i=1;i<=n;i++) maxx=max(maxx,f[i]);
printf("%lld\n",maxx);
}