图论
A - 数据结构实验之图论一:基于邻接矩阵的广度优先搜索遍历
题目
Description
给定一个无向连通图,顶点编号从0到n-1,用广度优先搜索(BFS)遍历,输出从某个顶点出发的遍历序列。(同一个结点的同层邻接点,节点编号小的优先遍历)
Input
输入第一行为整数n(0< n <100),表示数据的组数。
对于每组数据,第一行是三个整数k,m,t(0<k<100,0<m<(k-1)*k/2,0< t<k),表示有m条边,k个顶点,t为遍历的起始顶点。
下面的m行,每行是空格隔开的两个整数u,v,表示一条连接u,v顶点的无向边。
Output
输出有n行,对应n组输出,每行为用空格隔开的k个整数,对应一组数据,表示BFS的遍历结果。
Sample
Input
1
6 7 0
0 3
0 4
1 4
1 5
2 3
2 4
3 5
Output
0 3 4 2 5 1
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int a[1100][1100],vis[1100];
int main()
{
int t;
cin>>t;
while(t--)
{
memset(a,0,sizeof(a));
int n,m,k;
cin>>n>>m>>k;
for(int i=0;i<m;i++)
{
int x,y;
cin>>x>>y;
a[x][y]=a[y][x]=1;
}
int top=0,rear=0;
int b[1100];
b[rear++]=k;
vis[k]=1;
int flag=0;
while(top<rear)
{
if(!flag)
{
cout<<b[top];
flag++;
}
else cout<<" "<<b[top];
for(int i=0;i<n;i++)
{
if(!vis[i]&&a[b[top]][i])
{
b[rear++]=i;
vis[i]=1;
}
}
top++;
}
}
return 0;
}
B - 数据结构实验之图论二:图的深度遍历
题目
Description
请定一个无向图,顶点编号从0到n-1,用深度优先搜索(DFS),遍历并输出。遍历时,先遍历节点编号小的。
Input
输入第一行为整数n(0 < n < 100),表示数据的组数。 对于每组数据,第一行是两个整数k,m(0 < k < 100,0 < m < k*k),表示有m条边,k个顶点。 下面的m行,每行是空格隔开的两个整数u,v,表示一条连接u,v顶点的无向边。
Output
输出有n行,对应n组输出,每行为用空格隔开的k个整数,对应一组数据,表示DFS的遍历结果。
Sample
Input
1
4 4
0 1
0 2
0 3
2 3
Output
0 1 2 3
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int n,m,t;
int a[1100][1100],vis[1100];
int flag;
void dfs(int x)
{
if(!flag)
{
cout<<x;
flag++;
}
else
cout<<" "<<x;
vis[x]=1;
for(int i=0; i<n; i++)
{
if(!vis[i]&&a[x][i])
{
dfs(i);
}
}
}
int main()
{
cin>>t;
while(t--)
{
flag=0;
memset(vis,0,sizeof(vis));
memset(a,0,sizeof(a));
cin>>n>>m;
for(int i=0; i<m; i++)
{
int x,y;
cin>>x>>y;
a[x][y]=a[y][x]=1;
}
for(int i=0;i<n;i++)
{
if(!vis[i])dfs(i);
}
cout<<endl;
}
return 0;
}
C - 数据结构实验之图论三:判断可达性
题目
Description
在古老的魔兽传说中,有两个军团,一个叫天灾,一个叫近卫。在他们所在的地域,有n个隘口,编号为1…n,某些隘口之间是有通道连接的。其中近卫军团在1号隘口,天灾军团在n号隘口。某一天,天灾军团的领袖巫妖王决定派兵攻打近卫军团,天灾军团的部队如此庞大,甚至可以填江过河。但是巫妖王不想付出不必要的代价,他想知道在不修建任何通道的前提下,部队是否可以通过隘口及其相关通道到达近卫军团展开攻击。由于n的值比较大(n<=1000),于是巫妖王找到了擅长编程的你 =_=,请你帮他解决这个问题,否则就把你吃掉变成他的魔法。为了拯救自己,赶紧想办法吧。
Input
输入包含多组,每组格式如下。
第一行包含两个整数n,m(分别代表n个隘口,这些隘口之间有m个通道)。
下面m行每行包含两个整数a,b;表示从a出发有一条通道到达b隘口(注意:通道是单向的)。
Output
如果天灾军团可以不修建任何通道就到达1号隘口,那么输出YES,否则输出NO。
Sample
Input
2 1
1 2
2 1
2 1
Output
NO
YES
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int n,m,t;
int a[1100][1100],vis[1100];
int flag;
void dfs(int x)
{
for(int i=1; i<=n; i++)
{
if(!vis[i]&&a[x][i])
{
vis[i]=1;
dfs(i);
}
}
}
int main()
{
while(cin>>n>>m)
{
memset(vis,0,sizeof(vis));
memset(a,0,sizeof(a));
for(int i=0; i<m; i++)
{
int x,y;
cin>>x>>y;
a[x][y]=1;
}
vis[n]=1;
dfs(n);
if(vis[1]==1)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
D - 数据结构实验之图论四:迷宫探索
题目
Description
有一个地下迷宫,它的通道都是直的,而通道所有交叉点(包括通道的端点)上都有一盏灯和一个开关;请问如何从某个起点开始在迷宫中点亮所有的灯并回到起点?
Input
连续T组数据输入,每组数据第一行给出三个正整数,分别表示地下迷宫的结点数N(1 < N <= 1000)、边数M(M <= 3000)和起始结点编号S,随后M行对应M条边,每行给出一对正整数,表示一条边相关联的两个顶点的编号。
Output
若可以点亮所有结点的灯,则输出从S开始并以S结束的序列,序列中相邻的顶点一定有边,否则只输出部分点亮的灯的结点序列,最后输出0,表示此迷宫不是连通图。
访问顶点时约定以编号小的结点优先的次序访问,点亮所有可以点亮的灯后,以原路返回的方式回到起点。
Sample
Input
1
6 8 1
1 2
2 3
3 4
4 5
5 6
6 4
3 6
1 5
Output
1 2 3 4 5 6 5 4 3 2 1
代码
这个题没看清题意,WA了几遍,题目没说每个节点只能走一次,所以边走边记录就行
#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int n,m,s,k,path[1010],flag,sum;
int a[1010][1010],vis[1010];
void dfs(int x)
{
vis[x]=1;
path[k++]=x;
for(int i=1; i<=n; i++)
{
if(!vis[i]&&a[i][x])
{
sum++;
dfs(i);
path[k++]=x;
}
}
}
int main()
{
int t;
cin>>t;
while(t--)
{
memset(vis,0,sizeof(vis));
memset(a,0,sizeof(a));
memset(path,0,sizeof(path));
k=0,flag=0,sum=0;
cin>>n>>m>>s;
for(int i=0; i<m; i++)
{
int u,v;
cin>>u>>v;
a[u][v]=a[v][u]=1;
}
dfs(s);
if(sum==n-1)
{
cout<<path[0];
for(int i=1; i<k; i++)
cout<<" "<<path[i];
cout<<endl;
}
else
{
for(int i=0; i<k; i++)
cout<<path[i]<<" ";
cout<<"0"<<endl;
}
}
return 0;
}
E - 数据结构实验之图论五:从起始点到目标点的最短步数(BFS)
题目
Description
在古老的魔兽传说中,有两个军团,一个叫天灾,一个叫近卫。在他们所在的地域,有n个隘口,编号为1…n,某些隘口之间是有通道连接的。其中近卫军团在1号隘口,天灾军团在n号隘口。某一天,天灾军团的领袖巫妖王决定派兵攻打近卫军团,天灾军团的部队如此庞大,甚至可以填江过河。但是巫妖王不想付出不必要的代价,他想知道在不修建任何通道的前提下,部队是否可以通过隘口及其相关通道到达近卫军团展开攻击;如果可以的话,最少需要经过多少通道。由于n的值比较大(n<=1000),于是巫妖王找到了擅长编程的你 =_=,请你帮他解决这个问题,否则就把你吃掉变成他的魔法。为了拯救自己,赶紧想办法吧。
Input
输入包含多组,每组格式如下。
第一行包含两个整数n,m(分别代表n个隘口,这些隘口之间有m个通道)。
下面m行每行包含两个整数a,b;表示从a出发有一条通道到达b隘口(注意:通道是单向的)。
Output
如果天灾军团可以不修建任何通道就到达1号隘口,那么输出最少经过多少通道,否则输出NO。
Sample
Input
2 1
1 2
2 1
2 1
Output
NO
1
代码
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
int a[1010][1010],n, m;;
int vis[1010], dis[1010];
void dijkstra(int s)
{
dis[s] = 0;
for (int i = 1; i <= n; i++)
{
int node = -1;
for (int j = 1; j <= n; j++)
{
if (!vis[j] && (dis[j] < dis[node] || node == -1))
node = j;
}
vis[node] = 1;
for (int j = 1; j <= n; j++)
{
if (a[node][j] == 1)
{
if (dis[j] > dis[node] + 1)
dis[j] = dis[node] + 1;
}
}
}
}
int main()
{
while (cin >> n >> m)
{
memset(a, 0, sizeof(a));
memset(vis, 0, sizeof(vis));
memset(dis, inf, sizeof(dis));
for (int i = 0; i < m; i++)
{
int x, y;
cin >> x >> y;
a[x][y] = 1;
}
dijkstra(n);
if (dis[1] == inf)cout << "NO" << endl;
else cout << dis[1] << endl;
}
return 0;
}
F - 数据结构实验之图论六:村村通公路
题目
Description
当前农村公路建设正如火如荼的展开,某乡镇政府决定实现村村通公路,工程师现有各个村落之间的原始道路统计数据表,表中列出了各村之间可以建设公路的若干条道路的成本,你的任务是根据给出的数据表,求使得每个村都有公路连通所需要的最低成本。
Input
连续多组数据输入,每组数据包括村落数目N(N <= 1000)和可供选择的道路数目M(M <= 3000),随后M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个村庄的编号和修建该道路的预算成本,村庄从1~N编号。
Output
输出使每个村庄都有公路连通所需要的最低成本,如果输入数据不能使所有村庄畅通,则输出-1,表示有些村庄之间没有路连通。
Sample
Input
5 8
1 2 12
1 3 9
1 4 11
1 5 3
2 3 6
2 4 9
3 4 4
4 5 6
Output
19
Hint
代码
#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int n,m;
int f[1010],vis[1010];
int findd(int x)
{
if(x==f[x])
return x;
else
return f[x]=findd(f[x]);
}
struct node
{
int u,v,w;
} a[1010];
bool cmp(node a,node b)
{
return a.w<b.w;
}
int main()
{
while(cin>>n>>m)
{
for(int i=0;i<=n;i++)
f[i]=i;
for(int i=0; i<m; i++)
{
cin>>a[i].u>>a[i].v>>a[i].w;
}
int cnt=0,sum=1;
sort(a,a+m,cmp);
for(int i=0; i<m; i++)
{
if(findd(a[i].u)!=findd(a[i].v))
{
sum++;
f[findd(a[i].u)]=findd(a[i].v);
cnt+=a[i].w;
}
}
if(sum==n)
cout<<cnt<<endl;
else cout<<-1<<endl;
}
return 0;
}
G - 数据结构实验之图论七:驴友计划
题目
Description
做为一个资深驴友,小新有一张珍藏的自驾游线路图,图上详细的标注了全国各个城市之间的高速公路距离和公路收费情况,现在请你编写一个程序,找出一条出发地到目的地之间的最短路径,如果有多条路径最短,则输出过路费最少的一条路径。
Input
连续T组数据输入,每组输入数据的第一行给出四个正整数N,M,s,d,其中N(2 <= N <= 500)是城市数目,城市编号从0~N-1,M是城市间高速公路的条数,s是出发地的城市编号,d是目的地的城市编号;随后M行,每行给出一条高速公路的信息,表示城市1、城市2、高速公路长度、收费额,中间以空格间隔,数字均为整数且不超过500,输入数据均保证有解。
Output
在同一行中输出路径长度和收费总额,数据间用空格间隔。
Sample
Input
1
4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20
Output
3 40
代码
#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int n,m,s,e;
int dis[504],vis[504],a[504][504],b[504][504],rmb[504];
void dijkstra(int s)
{
dis[s]=0;
rmb[s]=0;
for(int i=0; i<n; i++)
{
int node=-1;
for(int j=0; j<n; j++)
{
if(!vis[j]&&(node==-1||dis[j]<dis[node]))
{
node=j;
}
}
vis[node]=1;
for(int j=0; j<n; j++)
{
if(dis[j]>dis[node]+a[node][j])
{
dis[j]=dis[node]+a[node][j];
rmb[j]=rmb[node]+b[node][j];
}
else if(dis[j]==dis[node]+a[node][j])
{
if(rmb[j]>rmb[node]+b[node][j])
{
rmb[j]=rmb[node]+b[node][j];
}
}
}
}
}
int main()
{
int t;
cin>>t;
while(t--)
{
memset(vis,0,sizeof(vis));
memset(a,inf,sizeof(a));
memset(b,inf,sizeof(b));
memset(dis,inf,sizeof(dis));
memset(rmb,inf,sizeof(rmb));
cin>>n>>m>>s>>e;
for(int i=0; i<n; i++)
{
a[i][i]=0;
b[i][i]=0;
}
for(int i=0; i<m; i++)
{
int u,v,w,q;
cin>>u>>v>>w>>q;
a[u][v]=a[v][u]=w;
b[u][v]=b[v][u]=q;
}
dijkstra(s);
cout<<dis[e]<<" "<<rmb[e]<<endl;
}
return 0;
}
H - 数据结构实验之图论八:欧拉回路
题目
Description
在哥尼斯堡的一个公园里,有七座桥将普雷格尔河中两个岛及岛与河岸连接起来。
能否走过这样的七座桥,并且每桥只走一次?瑞士数学家欧拉最终解决了这个问题并由此创立了拓扑学。欧拉通过对七桥问题的研究,不仅圆满地回答了哥尼斯堡七桥问题,并证明了更为广泛的有关一笔画的三条结论,人们通常称之为欧拉定理。对于一个连通图,通常把从某结点出发一笔画成所经过的路线叫做欧拉路。人们又通常把一笔画成回到出发点的欧拉路叫做欧拉回路。具有欧拉回路的图叫做欧拉图。
你的任务是:对于给定的一组无向图数据,判断其是否成其为欧拉图?
Input
连续T组数据输入,每组数据第一行给出两个正整数,分别表示结点数目N(1 < N <= 1000)和边数M;随后M行对应M条边,每行给出两个正整数,分别表示该边连通的两个结点的编号,结点从1~N编号。
Output
若为欧拉图输出1,否则输出0。
Sample
Input
1
6 10
1 2
2 3
3 1
4 5
5 6
6 4
1 4
1 6
3 4
3 6
Output
1
代码
先用dfs判断连通性,然后在判断每个节点的度
#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int n,m;
int a[1010][1010],vis[1010],d[1010];
void dfs(int x)
{
vis[x]=1;
for(int i=1; i<=n; i++)
{
if(!vis[i]&&a[x][i])
dfs(i);
}
}
int main()
{
int t;
cin>>t;
while(t--)
{
memset(d,0,sizeof(d));
memset(a,0,sizeof(a));
memset(vis,0,sizeof(vis));
cin>>n>>m;
for(int i=0; i<m; i++)
{
int u,v;
cin>>u>>v;
d[u]++;
d[v]++;
a[u][v]=a[v][u]=1;
}
int sum=0;
for(int i=1; i<=n; i++)
{
if(!vis[i])
{
dfs(i);
sum++;
}
}
int flag=0;
if(sum==1)
{
for(int i=1; i<=n; i++)
{
if(d[i]%2!=0)
{
flag++;
break;
}
}
if(!flag)cout<<1<<endl;
else cout<<0<<endl;
}
else cout<<0<<endl;
}
return 0;
}
I - 数据结构实验之图论九:最小生成树
题目
Description
有n个城市,其中有些城市之间可以修建公路,修建不同的公路费用是不同的。现在我们想知道,最少花多少钱修公路可以将所有的城市连在一起,使在任意一城市出发,可以到达其他任意的城市。
Input
输入包含多组数据,格式如下。
第一行包括两个整数n m,代表城市个数和可以修建的公路个数。(n <= 100, m <=10000)
剩下m行每行3个非负整数a b c,代表城市a 和城市b之间可以修建一条公路,代价为c(城市编号从1到n)。
Output
每组输出占一行,仅输出最小花费。
Sample
Input
3 2
1 2 1
1 3 1
1 0
Output
2
0
代码
#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int n,m;
int f[1010],vis[1010];
int findd(int x)
{
if(x==f[x])
return x;
else
return f[x]=findd(f[x]);
}
struct node
{
int u,v,w;
} a[10100];
bool cmp(node a,node b)
{
return a.w<b.w;
}
int main()
{
while(cin>>n>>m)
{
for(int i=0;i<=n;i++)
f[i]=i;
for(int i=0; i<m; i++)
{
cin>>a[i].u>>a[i].v>>a[i].w;
}
int cnt=0;
sort(a,a+m,cmp);
for(int i=0; i<m; i++)
{
if(findd(a[i].u)!=findd(a[i].v))
{
f[findd(a[i].u)]=findd(a[i].v);
cnt+=a[i].w;
}
}
cout<<cnt<<endl;
}
return 0;
}
J - 数据结构实验之图论十:判断给定图是否存在合法拓扑序列
题目
Description
给定一个有向图,判断该有向图是否存在一个合法的拓扑序列。
Input
输入包含多组,每组格式如下。
第一行包含两个整数n,m,分别代表该有向图的顶点数和边数。(n<=10)
后面m行每行两个整数a b,表示从a到b有一条有向边。
Output
若给定有向图存在合法拓扑序列,则输出YES;否则输出NO。
Sample
Input
1 0
2 2
1 2
2 1
Output
YES
NO
代码
生猛的拓扑排序,判断一个图中有没有环
#include<bits/stdc++.h>
using namespace std;
int n,m;
int main()
{
while(cin>>n>>m)
{
int a[504][504]={
0},vis[504]={
0},b[504]={
0};
if(m==0)cout<<"YES"<<endl;
else
{
for(int i=0; i<m; i++)
{
int x,y;
cin>>x>>y;
a[x][y]=1;
b[y]++;
}
int cnt=0;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(!vis[j]&&b[j]==0)
{
vis[j]=1;
cnt++;
for(int k=1; k<=n; k++)
{
if(a[j][k]==1)b[k]--;
}
}
}
}
if(cnt!=n)cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
}
return 0;
}
还有四个题后续补上