说明
主要考察建图,图的遍历以及求最小生成树。都还是比较简单的,后面就直接上代码了。
最小生成树采用prim还是kruskal算法要看题目怎么给出数据,如果以邻接矩阵的形式给出,采用prim算法比较合适,如果以边和边的权重的形式给出,则采用kruskal算法比较合适。例如这里的D和E题采用kruskal算法比较好,但是不代表用prim算法不能做,我这两个题给出的就是prim的解法,但是某些题用另一个算法极不方便,因此还是建议采用题目所暗示我们应使用的方法最佳。
题目列表
问题 A: 图的遍历—深度优先搜索—邻接矩阵
参考题解:
#include <iostream>
#include <functional>
int main(){
std::cin.tie(nullptr)->sync_with_stdio(false);
constexpr int MAX_N = 5e1+5;
int g[MAX_N][MAX_N] {};
bool vis[MAX_N] {};
int n;std::cin >> n;
for(int i = 0;i<n;i++){
for(int j = 0;j<n;j++){
std::cin >> g[i][j];
}
}
using Dfs = std::function<void(int)>;
Dfs dfs = [&](int u) {
std::cout << u << ' ';
for(int i = 0;i<n;i++){
if(g[u][i]&&!vis[i]) vis[i]=true,dfs(i);
}
};
vis[0] = true;
dfs(0);
std::cout << '\n';
return 0;
}
问题 B: 图的遍历—DFS—已知边
参考题解:
#include <iostream>
#include <functional>
int main(){
std::cin.tie(nullptr)->sync_with_stdio(false);
constexpr int MAX_N = 1e1+5;
int g[MAX_N][MAX_N] {};
bool vis[MAX_N] {};
int n,m;std::cin >> n >> m;
while(m--){
int x,y;std::cin >> x >> y;
g[x][y]=g[y][x]=1;
}
using Dfs = std::function<void(int)>;
Dfs dfs = [&](int u){
std::cout << u << ' ';
for(int i = 1;i<=n;i++){
if(g[u][i]&&!vis[i]) vis[i]=true,dfs(i);
}
};
vis[1] = true;
dfs(1);
std::cout << '\n';
return 0;
}
问题 C: 图的遍历—广度优先搜索
参考题解:
#include <iostream>
#include <queue>
int main(){
std::cin.tie(nullptr)->sync_with_stdio(false);
constexpr int MAX_N = 5e1+5;
int g[MAX_N][MAX_N] {};
bool vis[MAX_N] {};
int n;std::cin >> n;
for(int i = 0;i<n;i++){
for(int j = 0;j<n;j++){
std::cin >> g[i][j];
}
}
auto bfs = [&](){
std::queue<int> q;
q.emplace(0);
vis[0] = true;
while(!q.empty()){
auto t = q.front();
q.pop();
std::cout << t << ' ';
for(int i = 0;i<n;i++){
if(!vis[i]&&g[t][i]){
vis[i] = true;
q.emplace(i);
}
}
}
};
bfs();
std::cout << '\n';
return 0;
}
问题 D: 最小生成树-局域网
参考题解:
#include <iostream>
#include <cstring>
#include <type_traits>
template<typename T1,typename T2>
typename std::common_type<T1,T2>::type min(T1 num1,T2 num2){
return num1>num2?num2:num1;
}
int main(){
std::cin.tie(nullptr)->sync_with_stdio(false);
constexpr int MAX_N = 1e2+5,INF = 0x3f3f3f3f;
int g[MAX_N][MAX_N];
int dist[MAX_N];
memset(g,0x3f,sizeof g);
bool vis[MAX_N] = {false};
int n,m;std::cin >> n >> m;
int ans = 0;
while(m--){
int x,y,w;std::cin >> x >> y >> w;
g[x][y]=g[y][x]=min(g[y][x],w);
ans+=w;
}
auto prim = [&]()->int{
memset(dist,0x3f,sizeof dist);
dist[1] = 0;
int ans = 0;
for(int i = 0;i<n;++i){
int t = -1;
for(int j = 1;j<=n;++j){
if(!vis[j]&&(t==-1||dist[t]>dist[j])) t = j;
}
if(dist[t]==INF) return INF;
ans+=dist[t];
vis[t] = true;
for(int j = 1;j<=n;++j) dist[j] = min(dist[j],g[t][j]);
}
return ans;
};
ans-=prim();
std::cout << ans << '\n';
return 0;
}
问题 E: 最小生成树-繁忙的都市
参考题解:
#include <iostream>
#include <cstring>
#include <type_traits>
template<typename T1,typename T2>
typename std::common_type<T1,T2>::type max(T1 num1,T2 num2){
return num1<num2?num2:num1;
}
template<typename T1,typename T2>
typename std::common_type<T1,T2>::type min(T1 num1,T2 num2){
return num1>num2?num2:num1;
}
int main(){
std::cin.tie(nullptr)->sync_with_stdio(false);
constexpr int MAX_N = 1e2+5,INF = 0x3f3f3f3f;
int g[MAX_N][MAX_N];
int dist[MAX_N];
memset(g,0x3f,sizeof g);
bool vis[MAX_N] = {false};
int n,m;std::cin >> n >> m;
while(m--){
int x,y,w;std::cin >> x >> y >> w;
g[x][y]=g[y][x]=min(g[y][x],w);
}
auto prim = [&]()->int{
memset(dist,0x3f,sizeof dist);
dist[1] = 0;
int ans = 0;
for(int i = 0;i<n;++i){
int t = -1;
for(int j = 1;j<=n;++j){
if(!vis[j]&&(t==-1||dist[t]>dist[j])) t = j;
}
if(dist[t]==INF) return INF;
ans = max(ans,dist[t]);
vis[t] = true;
for(int j = 1;j<=n;++j) dist[j]=min(dist[j],g[t][j]);
}
return ans;
};
std::cout << n-1 << ' ' << prim() << '\n';
return 0;
}
问题 F: 最小生成树-联络员
参考题解:
#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>
constexpr int MAX_N = 2e3+5,MAX_M = 1e4+5,INF = 0x3f3f3f3f;
struct edge{
int x,y,w;
bool operator < (const edge& W){
return w<W.w;
}
edge(int _x,int _y,int _w):x(_x),y(_y),w(_w){}
};
std::vector<edge> edges;
int fa[MAX_N];
int main(){
std::cin.tie(nullptr)->sync_with_stdio(false);
int n,m;std::cin >> n >> m;
for(int i = 1;i<=n;++i) fa[i] = i;
using Find = std::function<int(int)>;
Find find = [&](int x){
if(x!=fa[x]) fa[x] = find(fa[x]);
return fa[x];
};
int ans = 0;
while(m--){
int t,x,y,w;std::cin >> t >> x >> y >> w;
if(t==1){
ans+=w;
fa[find(x)] = find(y);
}else{
edges.emplace_back(x,y,w);
}
}
auto kruskal = [&](){
std::sort(edges.begin(),edges.end());
for(int i = 0;i<edges.size();++i){
int fx = find(edges[i].x),fy = find(edges[i].y),w = edges[i].w;
if(fx!=fy){
fa[fx] = fy;
ans+=w;
}
}
};
kruskal();
std::cout << ans << '\n';
return 0;
}
问题 G: 最小生成树-连接格点
参考题解:
#include <iostream>
#include <functional>
constexpr int MAX_N = 1e3+5;
int fa[MAX_N*MAX_N];
int main(){
std::cin.tie(nullptr)->sync_with_stdio(false);
using Find = std::function<int(int)>;
Find find = [&](int x)->int{
if(x!=fa[x]) fa[x] = find(fa[x]);
return fa[x];
};
int n,m;std::cin >> n >> m;
for(int i = 0;i<=n*m;++i) fa[i] = i;
int x1,y1,x2,y2;
while(std::cin >> x1 >> y1 >> x2 >> y2){
fa[find((x1-1)*m+y1)] = find((x2-1)*m+y2);
}
int ans = 0;
auto kruskal = [&]()->void{
for(int i = 1;i<n;++i){
for(int j = 1;j<=m;++j){
int dx = find((i-1)*m+j),dy = find(i*m+j);
if(dx!=dy){
++ans;
fa[dx] = dy;
}
}
}
for(int i = 1;i<=n;++i){
for(int j = 1;j<m;++j){
int dx = find((i-1)*m+j),dy = find((i-1)*m+j+1);
if(dx!=dy){
ans+=2;
fa[dx] = dy;
}
}
}
};
kruskal();
std::cout << ans << '\n';
return 0;
}
问题 H: 最小生成树-最短网络
参考题解:
#include <iostream>
#include <cstring>
#include <type_traits>
template<typename T1,typename T2>
typename std::common_type<T1,T2>::type min(T1 num1,T2 num2){
return num1>num2?num2:num1;
}
int main(){
std::cin.tie(nullptr)->sync_with_stdio(false);
constexpr int MAX_N = 1e2+5,INF = 0x3f3f3f3f;
int g[MAX_N][MAX_N];
int dist[MAX_N];
bool vis[MAX_N] {};
int n;std::cin >> n;
for(int i = 1;i<=n;++i){
for(int j = 1;j<=n;++j){
std::cin >> g[i][j];
}
}
auto prim = [&]()->int{
memset(dist,0x3f,sizeof dist);
int res = 0;
dist[1] = 0;
for(int i = 0;i<n;++i){
int t = -1;
for(int j = 1;j<=n;++j){
if(!vis[j]&&(t==-1||dist[j]<dist[t])) t = j;
}
if(dist[t]==INF) return INF;
vis[t] = true;
res+=dist[t];
for(int j = 1;j<=n;++j) dist[j]=min(dist[j],g[t][j]);
}
return res;
};
std::cout << prim() << '\n';
return 0;
}
问题 I: 最小生成树-最优布线问题
参考题解:
#include <iostream>
#include <cstring>
#include <type_traits>
template<typename T1,typename T2>
typename std::common_type<T1,T2>::type min(T1 num1,T2 num2){
return num1>num2?num2:num1;
}
int main(){
std::cin.tie(nullptr)->sync_with_stdio(false);
constexpr int MAX_N = 1e2+5,INF = 0x3f3f3f3f;
int g[MAX_N][MAX_N];
int dist[MAX_N];
bool vis[MAX_N] {};
int n;std::cin >> n;
for(int i = 1;i<=n;++i){
for(int j = 1;j<=n;++j){
std::cin >> g[i][j];
}
}
auto prim = [&]()->int{
memset(dist,0x3f,sizeof dist);
int res = 0;
dist[1] = 0;
for(int i = 0;i<n;++i){
int t = -1;
for(int j = 1;j<=n;++j){
if(!vis[j]&&(t==-1||dist[j]<dist[t])) t = j;
}
if(dist[t]==INF) return INF;
vis[t] = true;
res+=dist[t];
for(int j = 1;j<=n;++j) dist[j]=min(dist[j],g[t][j]);
}
return res;
};
std::cout << prim() << '\n';
return 0;
}