既然都有大佬用spfa跑最长链了,那么怎么少得了拓扑排序呢
主要感觉和P1137旅行计划没啥区别
对于任务A,如果它的结束时间(包括休息)end+R >= 任务B的 begin
那么说明可以形成继承关系,连一条从A到B的有向边,顺便计算B入度++
记dp[i]表示以i为终点的最长链,以上面的AB举例
dp[B]=max(dp[B],dp[A]+w[B]); 取max因为B的前驱点可能不止一个
坑点大概就是连边条件>=不是>吧,,似乎>只有80…,因为结束时间不挤奶,所以有效时间只是 [ l , r-1 ] ,可得最终休息结束时间在r+R-1;
其他没啥细节,看代码吧
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
using namespace std;
const int maxn = 1024;// m范围
typedef long long ll;
struct RNG
{
int be,en,w;
}task[maxn];
struct EDG// 我喜欢结构体
{
int to,next;
}edge[maxn*maxn];
int n,m,r;// 基础变量
int dp[maxn],rd[maxn],ans=-1;// 拓扑+dp变量
int cnt,head[maxn];// 前向星变量
bool cmp(RNG a,RNG b)// 排序方便连边
{
return a.be<b.be;
}
void add(ll from,ll to)// 加边
{
edge[++cnt].to=to;
edge[cnt].next=head[from];
head[from]=cnt;
}
void toopsort()// 朴实无华的拓扑排序
{
queue<int>q;
for(int i=1;i<=m;i++)
if(!rd[i])// 将每一个可以作为起点的点扔进队列,并初始化dp值
{
q.push(i);
dp[i]=task[i].w;
}
while(!q.empty())
{
int f1=q.front();
q.pop();
for(int i=head[f1];i!=-1;i=edge[i].next)
{
int to=edge[i].to;
dp[to]=max(dp[to],dp[f1]+task[to].w);// dp
ans=max(ans,dp[to]);
if(--rd[to]==0) q.push(to);
}
}
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d%d",&n,&m,&r);
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
task[i].be=x; task[i].en=y+r; task[i].w=z;
}
sort(task+1,task+1+m,cmp);// 排序方便连边
for(int i=1;i<=m;i++)// 连边
for(int j=i+1;j<=m;j++)
if(task[j].be>=task[i].en)
{
add(i,j);
rd[j]++;
}
toopsort();// 拓扑排序
printf("%d",ans);// 输出,结束
return 0;
}