洛谷-数据结构1-4-图的基本应用1

P5318 【深基18.例3】查找文献

题目描述

小 K 喜欢翻看洛谷博客获取知识。每篇文章可能会有若干个(也有可能没有)参考文献的链接指向别的博客文章。小 K 求知欲旺盛,如果他看了某篇文章,那么他一定会去看这篇文章的参考文献(如果他之前已经看过这篇参考文献的话就不用再看它了)。

假设洛谷博客里面一共有 n(1≤n≤105) 篇文章(编号为 1 到 n)以及 m(1≤m≤106) 条参考文献引用关系。目前小 K 已经打开了编号为 1 的一篇文章,请帮助小 K 设计一种方法,使小 K 可以不重复、不遗漏的看完所有他能看到的文章。

这边是已经整理好的参考文献关系图,其中,文献 X→Y 表示文章 X 有参考文献 Y。不保证编号为 1 的文章没有被其他文章引用。

请对这个图分别进行 DFS 和 BFS,并输出遍历结果。如果有很多篇文章可以参阅,请先看编号较小的那篇(因此你可能需要先排序)。

输入格式

共 m+1 行,第 1 行为 2 个数,n 和 m,分别表示一共有 n(1≤n≤105) 篇文章(编号为 1 到 n)以及m(1≤m≤106) 条参考文献引用关系。

接下来 m 行,每行有两个整数 X,Y 表示文章 X 有参考文献 Y。

输出格式

共 2 行。

第一行为 DFS 遍历结果,第二行为 BFS 遍历结果。

输入输出样例

输入 #1复制

复制代码
8 9
1 2
1 3
1 4
2 5
2 6
3 7
4 7
4 8
7 8

输出 #1复制

复制代码
1 2 5 6 3 7 8 4 
1 2 3 4 5 6 7 8 

实现代码:

cpp 复制代码
#include<iostream>  
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;  
struct edge{      
	int u,v;
}; 
vector <int> e[100001];  
vector <edge> s;
bool vis1[100001]={0},vis2[100001]={0}; 
bool cmp(edge x,edge y){ 
	if(x.v==y.v)
	return x.u<y.u;
	else return x.v<y.v;
}
void dfs(int x){  
	vis1[x]=1;
	cout<<x<<" ";
	for(int i=0;i<e[x].size();i++){
		int point=s[e[x][i]].v;
		if(!vis1[point]){
			dfs(point);
		}
	}
}
void bfs(int x){  
	queue <int> q;
	q.push(x);
	cout<<x<<" ";
	vis2[x]=1;
	while(!q.empty()){
		int fro=q.front();
		for(int i=0;i<e[fro].size();i++){
			int point=s[e[fro][i]].v;
			if(!vis2[point]){
				q.push(point); 
				cout<<point<<" ";
				vis2[point]=1;
			}
		}
		q.pop();
	}
}
int main(){
	int n,m;  
	cin>>n>>m; 
	for(int i=0;i<m;i++){
		int uu,vv;
		cin>>uu>>vv;
		s.push_back((edge){uu,vv});   
	}
	sort(s.begin(),s.end(),cmp); 
	for(int i=0;i<m;i++)   
		e[s[i].u].push_back(i); 
	dfs(1);   
	cout<<endl;
	bfs(1);   
}

P3916 图的遍历

题目描述

给出 N 个点,M 条边的有向图,对于每个点 v,令 A(v) 表示从点 v 出发,能到达的编号最大的点。现在请求出 A(1),A(2),...,A(N) 的值。

输入格式

第 1 行 2 个整数 N,M,表示点数和边数。

接下来 M 行,每行 2 个整数 Ui​,Vi​,表示边 (Ui​,Vi​)。点用 1,2,...,N 编号。

输出格式

一行 N 个整数 A(1),A(2),...,A(N)。

输入输出样例

输入 #1复制

复制代码
4 3
1 2
2 4
4 3

输出 #1复制

复制代码
4 4 3 4

说明/提示

  • 对于 60% 的数据,1≤N,M≤103。
  • 对于 100% 的数据,1≤N,M≤105。

实现代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+10;
vector<int> a[N];
int vis[N];
int maxn;
void dfs(int x,int maxt){
	if(vis[x]) return;
	vis[x]=maxt;
	for(int j=0;j<a[x].size();j++){
		if(vis[a[x][j]]==0) {
			dfs(a[x][j],maxt);
		}
	}
}
signed main(){
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=m;i++) {
		int x,y;
		cin>>x>>y;
		a[y].push_back(x);
	}
	for(int i=n;i>=1;i--){
		dfs(i,i);
	}
	for(int i=1;i<=n;i++)	 cout<<vis[i]<<" ";
	return 0;
}

P1113 [USACO02FEB] 杂务

题目描述

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

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

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

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

输入格式

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

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

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

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

输出格式

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

输入输出样例

输入 #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

实现代码:

cpp 复制代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,l,t,ans[10005],maxans;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%d",&i);
        scanf("%d",&l);
        int tmp=0;
        while(scanf("%d",&t)&&t)
            tmp=max(ans[t],tmp);
        ans[i]=tmp+l;
        maxans=max(ans[i],maxans);
    } 
    printf("%d\n",maxans);
    return 0;
 } 

P4017 最大食物链计数

题目背景

你知道食物链吗?Delia 生物考试的时候,数食物链条数的题目全都错了,因为她总是重复数了几条或漏掉了几条。于是她来就来求助你,然而你也不会啊!写一个程序来帮帮她吧。

题目描述

给你一个食物网,你要求出这个食物网中最大食物链的数量。

(这里的"最大食物链",指的是生物学意义上的食物链 ,即最左端是不会捕食其他生物的生产者,最右端是不会被其他生物捕食的消费者。)

Delia 非常急,所以你只有 1 秒的时间。

由于这个结果可能过大,你只需要输出总数模上 80112002 的结果。

输入格式

第一行,两个正整数 n、m,表示生物种类 n 和吃与被吃的关系数 m。

接下来 m 行,每行两个正整数,表示被吃的生物 A 和吃 A 的生物 B。

输出格式

一行一个整数,为最大食物链数量模上 80112002 的结果。

输入输出样例

输入 #1复制

复制代码
5 7
1 2
1 3
2 3
3 5
2 5
4 5
3 4

输出 #1复制

复制代码
5

说明/提示

各测试点满足以下约定:

测试点编号 n m
1,2 ≤40 ≤400
3,4 ≤100 ≤2×103
5,6 ≤103 ≤6×104
7,8 ≤2×103 ≤2×105
9,10 ≤5×103 ≤5×105

对于 100% 的数据,1≤n≤5×103,1≤m≤5×105

【补充说明】

数据中不会出现环,满足生物学的要求。(感谢 @AKEE)

实现代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1000001;
const int mod=80112002;
queue<int> q; 
int d[maxn],in[maxn],eat[maxn],head[maxn];
int n,m,tot,ans;
struct E{
	int to,nxt;
}e[maxn];
inline void add(int u,int v)
{
	e[++tot].to=v;
	e[tot].nxt=head[u];
	head[u]=tot;
}
inline void topo()
{
	for(int i=1;i<=n;i++)
	{
		if(in[i]==0)
		{
			q.push(i);
			d[i]++;
		}
	}
	while(!q.empty())
	{
		int p=q.front();
		q.pop();
		for(int i=head[p];i;i=e[i].nxt)
		{
			int go=e[i].to;
			d[go]=(d[go]+d[p])%mod;
			in[go]--;
			if(in[go]==0)
			q.push(go);
		}
	}
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		int a,b;
		cin>>a>>b;
		add(a,b);
		in[b]++;
		eat[a]++;
	}
	topo(); 
	for(int i=1;i<=n;i++)
	{
		if(eat[i]==0)
		ans=(ans+d[i])%mod;
	}
	cout<<ans;
}

P1807 最长路

题目描述

设 G 为有 n 个顶点的带权有向无环图,G 中各顶点的编号为 1 到 n,请设计算法,计算图 G 中 1,n 间的最长路径。

输入格式

输入的第一行有两个整数,分别代表图的点数 n 和边数 m。

第 2 到第 (m+1) 行,每行 3 个整数 u,v,w(u<v),代表存在一条从 u 到 v 边权为 w 的边。

输出格式

输出一行一个整数,代表 1 到 n 的最长路。

若 1 无法到达 n,请输出 −1。

输入输出样例

输入 #1复制

复制代码
2 1
1 2 1

输出 #1复制

复制代码
1

说明/提示

【数据规模与约定】

  • 对于 20%的数据,n≤100,m≤103。
  • 对于 40% 的数据,n≤103,m≤104。
  • 对于 100% 的数据,1≤n≤1500,0≤m≤5×104,1≤u,v≤n,−105≤w≤105。

实现代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int n,m,in[1505];
vector<int>g[1505];
vector<int>d[1505];
queue<int>q;
int v[1505];
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		int ff,tt,dd;
		cin>>ff>>tt>>dd;
		g[ff].push_back(tt);
		d[ff].push_back(dd);
		in[tt]++;
	}
	for(int i=2;i<=n;i++)
	{
		v[i]=-1e9;
		if(!in[i]) q.push(i);
	}
	while(!q.empty())
	{
		int x=q.front();
		q.pop();
		for(int i=0;i<g[x].size();i++)
			if(!--in[g[x][i]]) q.push(g[x][i]);
	}
	q.push(1);
	while(!q.empty())
	{
		int x=q.front();
		q.pop();
		for(int i=0;i<g[x].size();i++)
		{
			if(v[g[x][i]]<v[x]+d[x][i]) v[g[x][i]]=v[x]+d[x][i];
			if(!--in[g[x][i]]) q.push(g[x][i]);
		}
	}
	if(v[n]==-1e9) cout<<"-1";
	else cout<<v[n];
	return 0;
}
相关推荐
我叫黑大帅2 小时前
为什么map查找时间复杂度是O(1)?
后端·算法·面试
炽烈小老头2 小时前
【每天学习一点算法 2026/04/20】除自身以外数组的乘积
学习·算法
程序猿编码2 小时前
给你的网络流量穿件“隐形衣“:手把手教你用对称加密打造透明安全隧道
linux·开发语言·网络·安全·linux内核
skilllite作者3 小时前
AI agent 的 Assistant Auto LLM Routing 规划的思考
网络·人工智能·算法·rust·openclaw·agentskills
aq55356003 小时前
编程语言三巨头:汇编、C++与PHP大比拼
java·开发语言
aq55356003 小时前
PHP vs Python:30秒看懂核心区别
开发语言·python·php
我是无敌小恐龙3 小时前
Java SE 零基础入门Day01 超详细笔记(开发前言+环境搭建+基础语法)
java·开发语言·人工智能·opencv·spring·机器学习
破浪前行·吴3 小时前
数据结构概述
数据结构·学习
码云数智-大飞4 小时前
零基础微信小程序制作平台哪个好
开发语言