【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=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch==‘-‘)    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-‘0‘;
        ch=getchar();
    }
    return num*f;
}

int f[1000000],h,t;

struct Edge{
    int next,to,d,w;
}edge[1000010];
int head[100100],num=0;
inline void add(int from,int to,int d,int w){
    edge[++num]=(Edge){head[from],to,d,w};
    head[from]=num;
}

int indl[10010];

int s[10001][1001],e[10001][1001];

int main(){
    int n=read(),m=read();
    for(int i=1;i<=m;++i){
        int from=read(),to=read(),d=read(),w=read();
        add(from,to,d,w);
        indl[to]++;
    }
    for(int i=2;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]==0)    f[++t]=to;
        }
    }
    h=0;t=1;
    f[1]=1;
    s[0][1]=e[0][1]=1;
    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=0;j<m-d;++j)    s[j+d][to]|=s[j][from];
            for(int j=0;j<m-d;++j)    e[j+w][to]|=e[j][from];
            indl[to]--;
            if(!indl[to])    f[++t]=to;
        }
    }
    for(int i=0;i<=m;++i){
        if(s[i][n]&&e[i][n]){
            printf("%d",i);
            return 0;
        }
    }
    printf("IMPOSSIBLE");
    return 0;
}
时间: 2024-07-29 15:31:34

【Luogu】P3116会议时间(拓扑排序,DP)的相关文章

[Luogu P3953] 逛公园 (最短路+拓扑排序+DP)

题面 传送门:https://www.luogu.org/problemnew/show/P3953 Solution 这是一道神题 首先,我们不妨想一下K=0,即求最短路方案数的部分分. 我们很容易可以想到一个做法,就是魔改迪杰斯特拉做法: 如果一个点可以更新到达其他点的距离,那个点的方案数就是这个点的方案数:如果一个点所更新出来的距离和之前的相等,那个点的方案数加等当前点的方案数. 用式子可以表现为: f[j]=f[i] (dis[j]>dis[i]+x)   f[j]+=f[i] (dis

POJ 3249 Test for Job 拓扑排序+DP

http://poj.org/problem?id=3249 题意: 给一个有向无环图DAG(不一定联通),每个点有权值,入度为0的点为起点,出度为0的点为终点,选择一个起点走到一个终点,使得路上的权和最大. 分析: dp[to] = max(dp[from]) + value[to],然后先拓扑排序保证状态正确转移即可,终点做标记,如果是终点则尝试更新答案. update:因为点权可以为负,所以程序里用dp[i] == -1表示未访问过该点是有问题的,不过没有遇上会卡掉这种情况的数据=.= 1

POJ 3249 拓扑排序+DP

貌似是道水题.TLE了几次.把所有的输入输出改成scanf 和 printf ,有吧队列改成了数组模拟.然后就AC 了.2333333.... Description: MR.DOG 在找工作的过程中呢.遇见了这样一个问题.有n个城市,m条小道.然后要从入度为0的点出发,出度为0的点结束,中途经过的城市呢,都是要付费的.负数表示花费.正数表示收益.然后让你求收益最大或者说花费最少的总值. 貌似.BFS和DFS都会超时.不妨一试.附代码: #include<stdio.h>#include<

POJ3249Test for Job(拓扑排序+DP)

题意就是给一个有向无环图,每个点都有一个权值,求从入度为0的点到出度为0点路径上经过点(包括起点终点)的权值和的最大值. 分析: 注意3点 1.本题有多组数据 2.可能有点的权值是负数,也就是结果可能为负,初值要设为负无穷. 3.入度或出度为0的点不止一个. 注意以上几点本题就很简单了,用到DP dis[i]:=max(dis[j],dis[i]+w[j])在拓扑排序过程同时进行即可. 考前练练拓扑排序和指针. 代码: program test; type point=^node; node=r

POJ3249 Test for Job(拓扑排序+dp)

Test for Job Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 10137   Accepted: 2348 Description Mr.Dog was fired by his company. In order to support his family, he must find a new job as soon as possible. Nowadays, It's hard to have a jo

NOIP2017 Day1 T3 逛公园(最短路+拓扑排序+DP)

神tm比赛时多清个零就有60了T T 首先跑出1起点和n起点的最短路,因为k只有50,所以可以DP.设f[i][j]表示比最短路多走i的长度,到j的方案数. 我们发现如果在最短路上的和零边会有后向性,怎么办呢?拓扑排序. 把最短路上的点和零边的点拉出来跑拓扑排序,如果有零环的话必定度数不为0,而且要注意零环必须在<=最短路+k的路径上才输出-1,这个就用刚刚跑出来的1起点到n起点的最短路来判断就好了. 然后先按拓扑序DP出i相同的,然后再DP不在最短路上或者零边的. #include<iost

【tarjan 拓扑排序 dp】bzoj1093: [ZJOI2007]最大半连通子图

思维难度不大,关键考代码实现能力.一些细节还是很妙的. Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径.若G'=(V',E')满足V'?V,E'是E中所有跟V'有关的边,则称G'是G的一个导出子图.若G'是G的导出子图,且G'半连通,则称G'为G的半连通子图.若G'是G所有半连通子图中包含节点数最多的,则称G'是G的最大半连通子图.给

[HAOI2012] 道路 - 最短路图,拓扑排序,dp

给定一个无向图,一条路径被称为最短路,当且仅当不存在从它的起点到终点的另外一条路径总长度比它小.两条最短路不同,当且仅当它们包含的道路序列不同.我们需要对每条道路的重要性进行评估,评估方式为计算有多少条不同的最短路经过该道路.\(n\leq 1500,m\leq 5000,w\leq 10000\) Solution 枚举每个点作为起点,跑出最短路径图,对其拓扑排序后,DP 统计出每个点发出和从起点到达该点的最短路的总数,然后扫一遍所有边统计答案即可. 注意可能有重边 #include <bit

Codefroces 919D Substring(拓扑排序+DP)

题目链接:http://codeforces.com/problemset/problem/919/D 题目大意:给你一张有向图,给你每个顶点上的字母和一些边,让你找出一条路径,路径上的相同字母数最多,输出最大相同字母数,若可以无穷多则输出-1(成环). 解题思路:因为是有向图,所以可以直接利用拓扑排序,拓扑排序过程中用f[i][j]记录到第i个点为止的路径,出现字母j的最大出现次数即可. 代码: 1 #include<iostream> 2 #include<cstdio> 3