Week9

# 查找文献

## 题目描述

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

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

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

![](https://cdn.luogu.com.cn/upload/image_hosting/f4n4tlhi.png)

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

## 输入格式

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

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

## 输出格式

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

## 样例 #1

### 样例输入 #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
```



解题思路:先用邻接表存图,然后根据终点大小从小到大排序,

​                   再用dfs和bfs,并用两个数组分别存遍历的数



完整代码如下:

```cpp
#include <bits/stdc++.h>
using namespace std;

const int maxn=1e6+5;

bool dvis[maxn],bvis[maxn];

vector<int> e[maxn];

int cnt,a[maxn],ans,b[maxn];

void dfs(int u);
void bfs(int u);

int main()
{
    int n,m;
    cin>>n>>m;
    int u,v;
    for(int i=1 ;i<=m; i++){
       cin>>u>>v;
       e[u].push_back(v);
    }//邻接表存图 
    for(int i=1; i<=n; i++) sort(e[i].begin(),e[i].end());//根据终点从小到大排序 
    dvis[1]=1;
    dfs(1);
    for(int i=0; i<=cnt; i++) cout<<a[i]<<" ";
    cout<<endl;
    bfs(1);
    for(int i=0; i<=ans; i++) cout<<b[i]<<" ";
    return 0;
}

void dfs(int u)
{
    a[cnt]=u;
    for(int i=0; i<e[u].size(); i++){
        if(!dvis[e[u][i]]){
            cnt++;
            dvis[e[u][i]]=1;
            dfs(e[u][i]);
        }
    }
}

void bfs(int u)
{
    queue <int> q;
    q.push(u);
    b[ans]=u;
    bvis[u]=1;
    while(!q.empty()){
        int t=q.front();
        q.pop();
        for(int i=0; i<e[t].size(); i++){
            if(!bvis[e[t][i]]){
                b[++ans]=e[t][i];
                q.push(e[t][i]);
                bvis[e[t][i]]=1;
            }
        }
    }
}
```







# 【模板】floyd

## 题目背景

模板题,无背景

## 题目描述

给出n个点,m条边的无向图,求每个点到其他点的距离之和%998244354的值

## 输入格式

第一行两个数n,m含义如上
从第二行开始,共m行,每行三个数x,y,l,代表从x到y点的长度为l

## 输出格式

n行,每行一个数,第i行代表点i到其他点的距离之和

## 样例 #1

### 样例输入 #1

```
2 1
1 2 4
```

### 样例输出 #1

```
4
4
```

## 样例 #2

### 样例输入 #2

```
4 5
1 2 1
1 3 2
2 3 2
3 4 3
2 4 4
```

### 样例输出 #2

```
8
7
7
12
```

## 提示

模板题,保证图联通
n<=500
m<=10000
1<=x,y<=n
l<=1e9





解题思路:floyd算法



完整代码如下:

```cpp
#include <bits/stdc++.h>
using namespace std;

const long long maxn=5005,mod=998244354,inf=0x3f3f3f3f;

long long d[maxn][maxn];

int main()
{
    int n,m;
    cin>>n>>m;
    long long x,y,l;
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++){
            d[i][j]=inf;
            d[i][i]=0;
        }
    }//一个点与另一个点的距离为inf时,表示两点不相连 
    for(int i=1; i<=m; i++){
        cin>>x>>y>>l;
         d[x][y]=min(l,d[x][y]);
         d[y][x]=min(l,d[y][x]);
    }//邻接矩阵存无向图,只要存入最小距离即可 
    for(int k=1; k<=n; k++){
        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++){
                d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
            }
        }
    }//floyd算法,即算出每一点到其它点的最短距离 
    for(int i=1; i<=n; i++){
        int sum=0;
        for(int j=1; j<=n; j++){
            if(d[i][j]!=inf) sum=(sum+d[i][j])%mod;
        }
        cout<<sum<<endl;
    }
    return 0;
}

```









# 【模板】单源最短路径(标准版)

## 题目背景

2018 年 7 月 19 日,某位同学在 [NOI Day 1 T1 归程](https://www.luogu.org/problemnew/show/P4768) 一题里非常熟练地使用了一个广为人知的算法求最短路。

然后呢?

100→60;

Ag→Cu;

最终,他因此没能与理想的大学达成契约。

小 F 衷心祝愿大家不再重蹈覆辙。

## 题目描述

给定一个n 个点,m 条有向边的带非负权图,请你计算从 s 出发,到每个点的距离。

数据保证你能从 s 出发到任意点。

## 输入格式

第一行为三个正整数 n, m, s。
第二行起 m 行,每行三个非负整数 u_i, v_i, w_i,表示从 u_i 到 v_i 有一条权值为 w_i 的有向边。

## 输出格式

输出一行 n 个空格分隔的非负整数,表示 s 到每个点的距离。

## 样例 #1

### 样例输入 #1

```
4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4
```

### 样例输出 #1

```
0 2 4 3
```

## 提示

样例解释请参考 [数据随机的模板题](https://www.luogu.org/problemnew/show/P3371)。

1 <= n <= 10^5;

1 <= m <= 2*10^5;

s = 1;

1 <= u_i, v_i<=n;

0 <= w_i <= 10 ^ 9,

0<=∑*w_i*<=10^9。

本题数据可能会持续更新,但不会重测,望周知。



解题思路:链式前向星存图,再用dijkstra算法的队列优化

​                  注意: 存图时要从1号位开始,不要从0开始



完整代码如下:

```cpp
#include <bits/stdc++.h>
using namespace std;

const int maxn=1e6+5;

int head[maxn],cnt=1,dis[maxn],n,m,s;
bool vis[maxn];

struct ed{
    int to,w,next;
}edge[maxn];

struct node{
    int dis,u;
    bool operator <(const node &a)const
    {
      return a.dis<dis;
    } 
};

priority_queue <node> q;

void add(int u,int v,int w);
void dijkstra();

int main()
{
    cin>>n>>m>>s;
    for(int i=1; i<=m; i++){
        int u,v,w;
        cin>>u>>v>>w;
        add(u,v,w);
    }//链式前向星存图 
    memset(dis,0x3f,sizeof(dis));//初始化距离 
    dijkstra();
    for(int i=1; i<=n; i++) cout<<dis[i]<<" ";
    return 0;
}

void add(int u,int v,int w)
{
    edge[cnt].to=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}

void dijkstra()
{
    dis[s]=0;
    q.push({0,s});
    while(!q.empty()){
        int u=q.top().u;
        q.pop();
        if(vis[u]) continue;
        vis[u]=1;
        for(int i=head[u]; i; i=edge[i].next){
            int v=edge[i].to;
            if(dis[v]>dis[u]+edge[i].w){
                dis[v]=dis[u]+edge[i].w;
                if(!vis[v]) q.push({dis[v],v});
            }
        }
    }
}
```






 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值