赞
踩
1.图中点的层次
给定一个n个点m条边的有向图,图中可能存在重边和自环。所有边的长度都是1,点的编号为1~n。
请你求出1号点到n号点的最短距离,如果从1号点无法走到n号点,输出-1。(其实就是一个权重都为1的图中1到n的最短路问题。)
输入格式
第一行包含两个整数n和m。
接下来m行,每行包含两个整数a和b,表示存在一条从a走到b的长度为1的边。
输出格式
输出一个整数,表示1号点到n号点的最短距离。
数据范围
1≤n,m≤10^5
输入样例:
4 5
1 2
2 3
3 4
1 3
1 4
输出样例:
1
#include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=100010,M=2*N; int n,m; int h[N],e[M],ne[M],idx; int d[N],q[N]; void add(int a,int b) { e[idx]=b,ne[idx]=h[a],h[a]=idx++; } int bfs() { int hh=0,tt=0; q[0]=1; memset(d,-1,sizeof d); d[1]=0; while(hh<=tt) { int t=q[hh++]; for(int i=h[t];i!=-1;i=ne[i]) { int j=e[i]; if(d[j]==-1) { d[j]=d[t]+1; q[++tt]=j; } } } return d[n]; } int main() { cin>>n>>m; memset(h,-1,sizeof h); for(int i=0;i<m;i++) { int a,b; cin>>a>>b; add(a,b); } cout<<bfs()<<endl; return 0; }
#include<iostream> #include<algorithm> #include<cstring> #include<queue> using namespace std; const int N = 1e5 + 10; int e[N], h[N], ne[N], d[N], idx; int n, m; void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx ++; } int bfs() { queue<int> q; q.push(1); memset(d, -1, sizeof d); d[1] = 0; while(!q.empty()) { int t = q.front(); q.pop(); for(int i = h[t]; i != -1; i = ne[i]) { int j = e[i]; if(d[j] == -1) { d[j] = d[t] + 1; q.push(j); } } } return d[n]; } int main() { cin >> n >> m; memset(h, -1, sizeof h); for(int i = 0; i < m ; i ++) { int a, b; cin >> a >> b; add(a, b); } cout << bfs() << endl; return 0; }
2.有向图的拓扑序列
给定一个 n 个点 m 条边的有向图,点的编号是 1 到 n,图中可能存在重边和自环。
请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出 −1。
若一个由图中所有点构成的序列 A 满足:对于图中的每条边 (x,y),x 在 A 中都出现在 y 之前,则称 A 是该图的一个拓扑序列。
输入格式
第一行包含两个整数 n 和 m。
接下来 m 行,每行包含两个整数 x 和 y,表示存在一条从点 x 到点 y 的有向边 (x,y)。
输出格式
共一行,如果存在拓扑序列,则输出任意一个合法的拓扑序列即可。
否则输出 −1。
数据范围
1≤n,m≤105
输入样例:
3 3
1 2
2 3
1 3
输出样例:
1 2 3
#include<bits/stdc++.h> using namespace std; const int N=1e5+10; int e[N],ne[N],h[N],idx,d[N],top[N],cnt; int a,b; void add(int a,int b) { e[idx]=b; ne[idx]=h[a]; h[a]=idx++; } bool topsort() { queue<int>r; for(int k=1;k<=a;k++) { if(d[k]==0) r.push(k); } int t; while(!r.empty()) { t=r.front(); top[cnt]=t; cnt++; r.pop(); for(int k=h[t];k!=-1;k=ne[k]) { int j=e[k]; d[j]--; if(d[j]==0) r.push(j); } } if(cnt<a-1) return 0; else return 1; } int main() { cin>>a>>b; memset(h,-1,sizeof(h)); for(int k=1;k<=b;k++) { int c,e; cin>>c>>e; add(c,e); d[e]++; } if(topsort()==0) cout<<"-1";//没有 else //有 { for(int k=0;k<a;k++) { cout<<top[k]<<" "; } } return 0; }
树的重心
给定一颗树,树中包含n个结点(编号1~n)和n-1条无向边。
请你找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。
重心定义:重心是指树中的一个结点,如果将这个点删除后,剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。
输入格式
第一行包含整数n,表示树的结点数。
接下来n-1行,每行包含两个整数a和b,表示点a和点b之间存在一条边。
输出格式
输出一个整数m,表示将重心删除后,剩余各个连通块中点数的最大值。
数据范围
1 ≤ n ≤ 1 0 5 1≤n≤10^5 1≤n≤105
9
1 2
1 7
1 4
2 8
2 5
4 3
3 9
4 6
4
#include<iostream> #include<algorithm> #include<cstring> using namespace std; const int N=1e5+10; //用链表结构存储每个点的边 int h[N]; //h[]用于存储每个点的头节点 int e[2*N]; //用于存储元素 因为是无向图 所以是双向边 应该乘2 int ne[2*N]; //存储链表的next值 int idx=0; int n; int ans=N; //记录重心子树的最小值 bool st[N]; //记录该点是否已经查找过 void add(int a,int b) //将b插入a中 a作为根 所以处在链表的最后 { e[idx]=b; ne[idx]=h[a]; h[a]=idx++; } int dfs(int u) //dfs过程寻找根的连通的点 { int size=0; //存放连通块中点的个数的最大值 st[u]=true; // 该点已经走过 int sum=1; //sum用于记录根子树的个数 for(int i=h[u];i!=-1;i=ne[i]) { int j=e[i]; if(!st[j]) { int s=dfs(j); size=max(size,s); sum+=s; } } size=max(size,n-sum); //通过画图可得n-m 即总的节点-根的子树 即为剩余的连通节点值 //而size为当前为根的子树的个数 通过比较确认连通块中点的最大数 ans=min(ans,size); return sum; } int main() { memset(h,-1,sizeof h); //初始化h[]表 -1表示空 scanf("%d",&n); for(int i=0;i<n-1;i++) //注意这里应该n-1, { //有些奇怪但是 仔细想想就明白 n是表示点的个数 而每行是输入两个点之间的边所以只需输入n-1行即可 int a,b; scanf("%d%d",&a,&b); add(a,b); add(b,a); } dfs(1); cout<<ans<<endl; return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。