此处记录图类型算法题的各种问题,以晴神的题库为基准
记录思路和题解核心
详细题目见晴问网站,感谢晴神
图类型算法题算是数据结构类型算法题中较为复杂的一种类型,概括来说有以下几种题型:
前三者为图的基础,一定要掌握。
后四者加粗为图中重要算法考点,掌握核心思想的同时也需要掌握其变换的多种题型。如最短路径问题就有很多小分支衍生问题。详情可见Dijsktra算法理解笔记。
图的问题非常需要归纳,做题时可以动手画一画会变得清晰很多。
下面以晴问题库为基础进行练习和总结。
核心:在于构建degree[ ](这个一般放在主函数前面定义)。无向图顶点的度是该顶点有几条边就是度多少。
#include
#define maxv 100
int degree[maxv]={0};
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){//核心循环
int a,b;
scanf("%d%d",&a,&b);
degree[a]++;
degree[b]++;
}
printf("%d",degree[0]);
for(int i=1;i<n;i++){
printf(" %d",degree[i]);
}
return 0;
}
注意点:注意这里输出的空格规范。算法题常出这些空格膈应人,所以小心为上。
#include
#define maxv 100
int inDegree[maxv]={0};
int outDegree[maxv]={0};
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
int a,b;
scanf("%d%d",&a,&b);
outDegree[a]++;
inDegree[b]++;
}
for(int i=0;i<n-1;i++){
printf("%d %d\n",inDegree[i],outDegree[i]);
}
printf("%d %d",inDegree[n-1],outDegree[n-1]);
return 0;
}
#include
#define maxv 100
int e[maxv][maxv]={0};
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
int a,b;
scanf("%d%d",&a,&b);
e[a][b]++;
e[b][a]++;//对称的加1
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
printf("%d",e[i][j]);
if(j<n-1) printf(" ");
}
printf("\n");
}
return 0;
}
题解里面有一个初始化邻接矩阵的语句,相对来说比较规范。
const int MAXN = 100;
int G[MAXN][MAXN];
int main() {
...
memset(G, 0, sizeof(G));
...
#include
#define maxv 100
int e[maxv][maxv]={0};
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
int a,b;
scanf("%d%d",&a,&b);
e[a][b]++;
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
printf("%d",e[i][j]);
if(j<n-1) printf(" ");
}
printf("\n");
}
return 0;
}
#include
#include
using namespace std;
const int maxv=100;
vector<int> G[maxv];//核心!!
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
int a,b;
scanf("%d%d",&a,&b);
G[a].push_back(b);
G[b].push_back(a);
}
for(int i=0;i<n;i++){
printf("%d(%d)",i,(int)G[i].size());
for(int j=0;j<G[i].size();j++){
printf(" %d",G[i][j]);
}
printf("\n");
}
return 0;
}
多说几句:vector添加操作为push_back(),返回个数为.size()【常用】
这篇博文说的较为好理解
#include
#include
using namespace std;
const int maxv=100;
vector<int> G[maxv];!
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
int a,b;
scanf("%d%d",&a,&b);
G[a].push_back(b);//核心区别!!
}
for(int i=0;i<n;i++){
printf("%d(%d)",i,(int)G[i].size());
for(int j=0;j<G[i].size();j++){
printf(" %d",G[i][j]);
}
printf("\n");
}
return 0;
}
bool vis[maxv];
void DFS(int u){
vis[u]=true;
for(int i=0;i<G[u].size();i++){
int v = G[u][i];
if(!vis[v]){
DFS(v);
}
}
DFS代码的核心是从邻接表的一个起点出发,一路向前,到头了再回头。
【完整代码】
#include
#include
using namespace std;
const int maxv=100;
vector<int> G[maxv];
bool vis[maxv];
void DFS(int u){
vis[u]=true;
for(int i=0;i<G[u].size();i++){
int v = G[u][i];
if(!vis[v]){
DFS(v);
}
}
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
int a,b;
scanf("%d%d",&a,&b);
G[a].push_back(b);
G[b].push_back(a);
}
int count=0;
for(int i=0;i<n;i++){
if(!vis[i]){
DFS(i);
count++;
}
}
printf("%d",count);
return 0;
}
#include
#include
using namespace std;
const int maxv=100;
vector<int> G[maxv];
bool vis[maxv];
void DFS(int u){
vis[u]=true;
for(int i=0;i<G[u].size();i++){
int v = G[u][i];
if(!vis[v]){
DFS(v);
}
}
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
int a,b;
scanf("%d%d",&a,&b);
G[a].push_back(b);
G[b].push_back(a);
}
int count=0;
for(int i=0;i<n;i++){
if(!vis[i]){
DFS(i);
count++;
}
}
printf(count==1?"Yes":"No");
return 0;
}
将这两种情况挑出来就可以了。
若访问完,那么这个起始点出发没有环。
bool isCircle(int u){
vis[u]=0;
for(int i=0;i<G[u].size();i++){
int v = G[u][i];
if(vis[v]==-1&&isCircle(v)) return true;
else if(vis[v]==0) return true;
}
vis[u]=1;
return false;
}
由此就可以书写【完整代码】。在主函数中,遍历整个图的每一个部分。判断该部分是否有环。
#include
#include
#include
using namespace std;
const int maxv=100;
vector<int> G[maxv];
int vis[maxv];
bool isCircle(int u){
vis[u]=0;
for(int i=0;i<G[u].size();i++){
int v = G[u][i];
if(vis[v]==-1&&isCircle(v)) return true;
else if(vis[v]==0) return true;
}
vis[u]=1;
return false;
}
int main(){
memset(vis,-1,sizeof(vis));
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
int a,b;
scanf("%d%d",&a,&b);
G[a].push_back(b);
}
int result=false;
for(int i=0;i<n;i++){
if(vis[i]==-1&&isCircle(i)){
result=true;
}
if(result) break;
}
printf(result?"Yes":"No");
return 0;
}
最新更新2021.1.12