题目链接
先上题目(多多关注_qaq )
题目描述
给出N个点,M条边的有向图,对于每个点v,求A(v)表示从点v出发,能到达的编号最大的点。
输入格式
第1 行,2 个整数N,M。
接下来M行,每行2个整数U_i,V_i,表示边(U_i,V_i)。点用1,2,⋯,N编号。
输出格式
N 个整数A(1),A(2),\cdots,A(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≤10^3
• 对于100% 的数据,1≤N,M≤10^5
本人暴力枚举的时候,自己编译时,发现只有样例过了,自己编的数据一个都没过(内心有点酸~~~),后来才发现其实是邻接表。
邻接表
先引入一下邻接矩阵吧。!!!不是邻接表
对于一张图~~
我们可以先弄一张表格,如下:
0 | 1 | 1 |
---|---|---|
1 | 0 | 0 |
1 | 0 | 0 |
其中,第i行第j列 表示 第i个城市和第j个城市是否联通(1为是,0为否)
由此,我们可得知 邻接矩阵具有对称性
————————————————————————————————————————
众所周知 邻接矩阵空间和时间复杂度都是N^2
让我们想一个问题:如果n为10^7呢?,那么将会有大量的空间被浪费。
————————————————————————————————————————
由此,神诞生了——邻接表~~~(此处省略巨多音效 )
简介:空间和时间复杂度就都是M。对于稀疏图来说,M要远远小于N^2。
假设有n个点,m条边
3 3
1 2
1 3
2 3
序号 | head | to | next |
---|---|---|---|
① | 2 | 2 | 0 |
② | 3 | 3 | 1 |
③ | 0 | 3 | 0 |
可以发现,从第i点开始遍历,就先找到head[i]的序号,再找到to[head[i]](为此点可以到达的边的序号,接下来,i就变成next[head[i]]————(本人第一次做TLE了无数次_QAQ)
上机程序片段
for(int i=head[x];i;i=t[i].next)
请查阅 https://blog.csdn.net/vocaloid01/article/details/76576822
https://so.csdn.net/so/search/all?q=%E9%82%BB%E6%8E%A5%E8%A1%A8&t=all&p=1&s=0&tm=0&lv=-1&ft=0&l=&u=
主要思路
对于一个点j,只需要把与j链接的点i感染(ans)注意是逆序,就不用判断了——QAQ
如果有强迫症的话,就用 mmax[x]=max(mmax[x],u);
接下来就是 插入要反过来 便于感染
add(b,a);
然后从大的点i开始遍历,找到一个点z开始感染(附值)——。而如果有一个比点i小的点j,也找到了点z,那就直接跳过(因为i>j)节约时间——qaq
if(mmax[x])return;
mmax[x]=u;
AC代码
#include<bits/stdc++.h>
using namespace std;
int n,m,a,b,x,y,c[100001],head[100001],mmax[100001],p;
struct abc{
int to,next;
}t[100001];
void dfs(int x,int u){
//深搜
if(mmax[x])return;
mmax[x]=u;//感染 mmax[x]=max(mmax[x],u);
for(int i=head[x];i;i=t[i].next){
dfs(t[i].to,u);
}
}
void add(int a,int b){
//插入
p++;
t[p].next=head[a];
head[a]=p;
t[p].to=b;
}
int main(){
cin>>m>>n;
for(int i=1;i<=n;i++){
cin>>a>>b;
add(b,a);
}
for(int u=m;u>=1;u--){
重点:注意是逆向 后面就不用max()了————啊哈哈~
dfs(u,u); //第二个u是为了“感染”
}
for(int i=1;i<=m;i++)cout<<mmax[i]<<" ";
//cout<<endl<<endl;
//for(int i=1;i<=m;i++)printf("%3d. %3d %3d %3d\n",i,head[i],t[i].to,t[i].next);
}
~白白-QAQ