1.基础练习 Huffman树
问题描述
GXUOJ | 基础练习 Huffman树
代码解析
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
priority_queue<int,vector <int>,greater<int> >pq;
for(int i=0;i<n;i++){
int value;
cin>>value;
pq.push(value);
}
int sum=0;
while(pq.size()>1){
int first=pq.top();pq.pop();
int second=pq.top();pq.pop();
int temp=first+second;
sum+=temp;
pq.push(temp);
}
cout<<sum;
}
2.数据结构-最小生成树
问题描述
GXUOJ | 数据结构-最小生成树
代码解析
#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=505;
//a[i][j] 表示节点 i 和节点 j 之间的边权重
int a[maxn][maxn];
int visit[maxn];
//dist[maxn] 存储从起始节点到其他节点的当前最短距离
int dist[maxn];
int n,m;
int u,v,w;
long long sum=0;
// prim算法核心函数,pos为起始节点
int prim(int pos){
// 将起始节点到自身的距离设为0
dist[pos]=0;
for(int i=1;i<=n;i++){
int cur=-1;
for(int j=1;j<=n;j++){
// 如果节点j未被访问,且(cur为-1 或者
//节点j到起始点的距离小于cur到起始点的距离)
if(!visit[j]&&(cur==-1||dist[j]<dist[cur])){
cur=j;
}
}
if(dist[cur]>=INF) return INF;
sum+=dist[cur];
visit[cur]=1;
for(int k=1;k<=n;k++){
if(!visit[k])
dist[k]=min(dist[k],a[cur][k]);
/*
假设起始节点为 s,最初 dist[k] 记录的是从 s 到 k 的某条路径的长度。
当我们将节点 cur 加入到最小生成树中后,发现从 s 经过 cur 到 k 的路径更短,
那么就更新 dist[k] 为从 s 经过 cur 到 k 的这个更短的距离。
这样,dist[k] 始终保持从起始节点到 k 的当前最短距离。
*/
}
}
return sum;
}
int main(){
cin>>n>>m;
memset(a,0x3f,sizeof(a));
memset(dist,0x3f,sizeof(dist));
for(int i=1;i<=m;i++){
cin>>u>>v>>w;
// 无向图,所以两个方向的边权都要更新
a[u][v]=a[v][u]=w;
}
int value=prim(1);
if(value>=INF) cout<<"Imp"<<endl;
else cout<<sum<<endl;
return 0;
}
3.最短路径
问题描述
GXUOJ | 最短路径
代码解析
#include<bits/stdc++.h>
using namespace std;
long long n, m, s, dis[2000005], vis[2000005];
// 定义节点结构体,包含两个整数x和y
struct node
{
int x, y;
};
// 定义一个vector数组g,用于存储每个节点的邻接节点
vector<node>g[2000005];
// 定义一个dijkstra函数,用于计算从节点z到其他节点的最短路径
void dijkstra(int z)
{
// 定义一个优先队列q,用于存储节点和对应的距离
priority_queue<pair<int, int>>q;
// 将dis数组初始化为无穷大
memset(dis, 0x3f, sizeof(dis));
// 将vis数组初始化为0
memset(vis, 0, sizeof(vis));
// 将起点z的距离设置为0
dis[z] = 0;
// 将起点z和距离0放入优先队列q中
q.push({ 0, z });
// 当优先队列q不为空时,执行循环
while (!q.empty())
{
// 取出优先队列q中的节点x和距离
int x = q.top().second;
q.pop();
// 如果节点x已经访问过,则跳过
if (vis[x]) continue;
// 将节点x标记为已访问
vis[x] = 1;
// 遍历节点x的邻接节点
for (auto to : g[x])
{
// 取出邻接节点k和距离l
int k = to.x;
int l = to.y;
// 如果从节点z到节点k的距离大于从节点z到节点x的距离加上距离l,则更新距离
if (dis[k] > dis[x] + l)
{
dis[k] = dis[x] + l;
// 如果节点k未被访问过,则将节点k和距离放入优先队列q中
if (vis[k] == 0)
{
q.push({ -dis[k], k });
}
}
}
}
}
int main()
{
// 输入节点数n、边数m和起点s
cin >> n >> m;
int start, end;
cin >> start >> end;
// 遍历每条边,输入边的两个端点和距离,并将距离存入邻接节点数组g中
for (int i = 1; i <= m; i++)
{
int u, v, w;
cin >> u >> v >> w;
g[u].push_back({ v, w });
}
// 调用dijkstra函数,计算从起点s到其他节点的最短路径
dijkstra(0);
cout << dis[end] - dis[start];
return 0;
}
4.小西加油
问题描述
GXUOJ | 小西加油
代码解析
#include <bits/stdc++.h>
#define MAX 10000 + 1
const int MAXN=10001;
using namespace std;
int n; //站点数量
double d; //每升油可以前进的距离
int v[MAXN]; //站点的距离
int a[MAXN]; //编号为i的站点一升油的价格为 ai元
int ans;
int main()
{
cin >> n >> d;
for (int i = 1; i <= n - 1; i++)
cin >> v[i];
for (int i = 1; i <= n; i++)
cin >> a[i];
double last = 0; //用于记录上一段行程结束后剩余的油量可行驶的距离比例
int price = a[1];
for (int i = 1; i <= n - 1; i++)
{
double dis = v[i] - d * last; // 计算当前段距离
int units = ceil(dis / d); // 计算当前段所需完整单位数量
last = units - dis / d; // 更新剩余距离比例
ans += price * units; // 累加当前段花费
if (a[i + 1] < price) // 若下一个位置价格更低
price = a[i + 1]; // 更新价格
}
cout << ans << endl;
return 0;
}
5.并查集应用:判圈
问题描述
GXUOJ | 并查集应用:判圈
代码解析
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1000;
int f[MAXN];
//并查集三要素,初始化,寻找父节点,合并并查集
void init(int n) {
for (int i = 0; i < n; i++) {
f[i] = i;//刚开始每个的父节点都是自己
}
}
int find(int x) {
return x == f[x] ? x : (f[x]=find(f[x]));
}
void merage(int x, int y) {
int fx = find(x);
int fy = find(y);
if (fx == fy) return; //在同一个组织力,不用合并
else
f[fx] = y;
}
int main()
{
int n, m,q;
cin >> n >> m >> q;
init(n);
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
merage(u, v);
}
for (int i = 0; i < q; i++) {
int u, v;
cin >> u >> v;
int fu = find(u);
int fv = find(v);
if (fu != fv)
cout << "NO"<<endl;
else
cout << "YES"<<endl;
}
}