【Luogu】P3116会议时间(拓扑排序,DP)

时间:2023-03-09 04:00:25
【Luogu】P3116会议时间(拓扑排序,DP)

  题目链接

  本题使用拓扑排序来规划DP顺序。设s[i][j]表示i步是否能走到j这个点,e[i][j]表示i步是否能走到j这个点——用第二条路径。因为要满足无后效性和正确性,只有第i个点已经全部更新完毕的时候才能用它来更新其他的点。所以用拓扑。

  代码如下

  

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
inline long long read(){
long long num=,f=;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-;
ch=getchar();
}
while(isdigit(ch)){
num=num*+ch-'';
ch=getchar();
}
return num*f;
} int f[],h,t; struct Edge{
int next,to,d,w;
}edge[];
int head[],num=;
inline void add(int from,int to,int d,int w){
edge[++num]=(Edge){head[from],to,d,w};
head[from]=num;
} int indl[]; int s[][],e[][]; int main(){
int n=read(),m=read();
for(int i=;i<=m;++i){
int from=read(),to=read(),d=read(),w=read();
add(from,to,d,w);
indl[to]++;
}
for(int i=;i<=n;++i)
if(!indl[i]) f[++t]=i;
while(h++<t){
int from=f[h];
for(int i=head[from];i;i=edge[i].next){
int to=edge[i].to;
indl[to]--;
if(indl[to]==) f[++t]=to;
}
}
h=;t=;
f[]=;
s[][]=e[][]=;
while(h++<t){
int from=f[h];
for(int i=head[from];i;i=edge[i].next){ int to=edge[i].to,d=edge[i].d,w=edge[i].w;
for(int j=;j<m-d;++j) s[j+d][to]|=s[j][from];
for(int j=;j<m-d;++j) e[j+w][to]|=e[j][from];
indl[to]--;
if(!indl[to]) f[++t]=to;
}
}
for(int i=;i<=m;++i){
if(s[i][n]&&e[i][n]){
printf("%d",i);
return ;
}
}
printf("IMPOSSIBLE");
return ;
}