【洛谷P1113】杂务

还是学习图论

这篇的重点在于拓扑排序
什么是拓扑排序?给定一个DAG(有向无环图),如果对于一个序列,这个图的每条边的出发点在序列中都在其到达点的后面,那么称这个序列为拓扑排序
那么,拓扑排序怎么求?
给定一个定义:入度 指一个点作为一条有向边的到达点的次数
可以证明,在DAG中,必定存在至少一个点,使得其入度为0
在建图并计算入度后,将入度为0的点入队,然后如果一个点的入度--之后入度为0,接着入队,直到队列为空
这样拓扑排序就算出来了
那么,拓扑排序有什么用?
就我目前所了解到的,1.用于判断图中是否存在环,如果拓扑排序序列小于节点数那么就存在环。
2.在图中的简单DP中有所运用
我们给出拓扑排序的模板代码:

#include<bits/stdc++.h>
using namespace std;
int n;
int x,y;
int cnt,tot;
int head[10005],ver[1005],nex[10005];
int a[10005];
int deg[1005];
void add(int x,int y){
    ver[++tot]=y;deg[y]++;
    nex[tot]=head[x],head[x]=tot;
}
void topsort(){
    queue<int>q;
    for(int i=1;i<=n;i++){
        if(deg[i]==0) q.push(i);
    }
    while(!q.empty()){
        int x=q.front();q.pop();
        a[++cnt]=x;
        for(int i=head[x];i;i=nex[i]){
            int y=ver[i];
            if(--deg[y]==0) q.push(y);
        }
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        while(cin>>x){
            if(x==0) break;
            else add(i,x);
        }
    }
    topsort();
    for(int i=1;i<=n;i++){
        cout<<a[i]<<' ';
    }
    system("pause");
    return 0;
}

下面,我们来看这道拓扑排序和DP结合的题目:

P1113 杂务

题目描述

John 的农场在给奶牛挤奶前有很多杂务要完成,每一项杂务都需要一定的时间来完成它。比如:他们要将奶牛集合起来,将他们赶进牛棚,为奶牛清洗乳房以及一些其它工作。尽早将所有杂务完成是必要的,因为这样才有更多时间挤出更多的牛奶。

当然,有些杂务必须在另一些杂务完成的情况下才能进行。比如:只有将奶牛赶进牛棚才能开始为它清洗乳房,还有在未给奶牛清洗乳房之前不能挤奶。我们把这些工作称为完成本项工作的准备工作。至少有一项杂务不要求有准备工作,这个可以最早着手完成的工作,标记为杂务 1

John 有需要完成的 n 个杂务的清单,并且这份清单是有一定顺序的,杂务 k (k>1) 的准备工作只可能在杂务 1k1 中。

写一个程序依次读入每个杂务的工作说明。计算出所有杂务都被完成的最短时间。当然互相没有关系的杂务可以同时工作,并且,你可以假定 John 的农场有足够多的工人来同时完成任意多项任务。

输入格式

第1行:一个整数 n (3n10,000),必须完成的杂务的数目;

2n+1 行,每行有一些用空格隔开的整数,分别表示:

  • 工作序号(保证在输入文件中是从 1n 有序递增的);
  • 完成工作所需要的时间 len (1len100)
  • 一些必须完成的准备工作,总数不超过 100 个,由一个数字 0 结束。有些杂务没有需要准备的工作只描述一个单独的 0

保证整个输入文件中不会出现多余的空格。

输出格式

一个整数,表示完成所有杂务所需的最短时间。

输入输出样例 #1

输入 #1

7
1 5 0
2 2 1 0
3 3 2 0
4 6 1 0
5 1 2 4 0
6 8 2 4 0
7 4 3 5 6 0

输出 #1

23

解法&&个人感想

首先要注意的是这道题的输入,每行的第一个点是入点 也就是add里面的y 而不是出点
所以加入度的时候要注意
然后,对于一般的拓扑排序和DP,我们一般将状态转移方程写在队列最后的判定外:
下面看代码 至于为什么是max一开始会看不懂 想一想就知道了
还有 N<=104是点的数目 建边数组要写大一点

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,tot,x,k;
int head[1000005],ver[1000005],nex[1000005];
int deg[10005],len[10005];
int dp[10005];
int ans;
void add(int x,int y){
    ver[++tot]=y;
    nex[tot]=head[x];
    head[x]=tot;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&k,&len[i]);
        while(cin>>x){
            if(x==0) break;
            else{
                add(x,i);
                deg[i]++;
            }
        }
    }
    queue<int>q;
    for(int i=1;i<=n;i++){
        if(!deg[i]) {
            dp[i]=len[i];
            q.push(i);
        }
    }
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int i=head[x];i;i=nex[i]){
            int y=ver[i];
            dp[y]=max(dp[y],dp[x]+len[y]);
            if(--deg[y]==0){
                q.push(y);
            }
        }
    }
    for(int i=1;i<=n;i++){
        ans=max(ans,dp[i]);        
    }
    printf("%d",ans);
    system("pause");
    return 0;
}
posted @   Elainafan  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示