【洛谷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 的农场在给奶牛挤奶前有很多杂务要完成,每一项杂务都需要一定的时间来完成它。比如:他们要将奶牛集合起来,将他们赶进牛棚,为奶牛清洗乳房以及一些其它工作。尽早将所有杂务完成是必要的,因为这样才有更多时间挤出更多的牛奶。
当然,有些杂务必须在另一些杂务完成的情况下才能进行。比如:只有将奶牛赶进牛棚才能开始为它清洗乳房,还有在未给奶牛清洗乳房之前不能挤奶。我们把这些工作称为完成本项工作的准备工作。至少有一项杂务不要求有准备工作,这个可以最早着手完成的工作,标记为杂务
John 有需要完成的
写一个程序依次读入每个杂务的工作说明。计算出所有杂务都被完成的最短时间。当然互相没有关系的杂务可以同时工作,并且,你可以假定 John 的农场有足够多的工人来同时完成任意多项任务。
输入格式
第1行:一个整数
第
- 工作序号(保证在输入文件中是从
到 有序递增的); - 完成工作所需要的时间
; - 一些必须完成的准备工作,总数不超过
个,由一个数字 结束。有些杂务没有需要准备的工作只描述一个单独的 。
保证整个输入文件中不会出现多余的空格。
输出格式
一个整数,表示完成所有杂务所需的最短时间。
输入输出样例 #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<=
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话