程序设计实践基础算法模板
程设 复习 代码
1.kruscal
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 100000
struct rec{int x,y,z;} edge[500010];
int fa[100010], n, m, ans;
bool operator <(rec a, rec b) {
return a.z < b.z;
}
int get(int x){
if(x == fa[x]) return x;
return fa[x] = get(fa[x]);
}
int main() {
cin >> n >> m;
for(int i = 1; i <= m; i++)
scanf("%d%d%d", &edge[i].x, &edge[i].y, &edge[i].z);
//按照边权排序
sort(edge + 1, edge + m + 1);
//并查集初始化
for (int i = 1; i <= n; i ++) fa[i] = i;
//求最小生成树 牛牛冲冲冲!
for (int i = 1; i <= m; i ++){
int x = get(edge[i].x);
int y = get(edge[i].y);
if (x == y) continue;
fa[x] = y;
ans += edge[i].z;
}
cout << ans << endl;
}
2.可能头文件
#include<bits/stdc++.h> //万能头文件,但是会拖慢程序运行速度
#include<cstdio>
#include <cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include <list> //STL 线性列表容器
#include <map> //STL 映射容器
#include <utility> //STL 通用模板类
#include <vector> //STL 动态数组容器
#include <stack> //STL 堆栈容器
3.prim算法
int a[3010][3010], d[3010], n, m, ans;
bool v[3010];
void prim(){
memset(d, 0x3f, sizeof(d));
memset(v, 0, sizeof(v));
d[1] = 0;
for(int i = 1; i < n; i++){
int x = 0;
for (int j = 1; j <= n; j++)
if(!v[j] && (x == 0 || d[j] < d[x]))
x = j;
v[x] = 1;
for(int y = 1; y <= n; y++)
if(!v[y])
d[y] = min(d[y], a[x][y]);
}
}
int main(){
cin >> n >> m;
//构建邻接矩阵
memset(a, 0x3f, sizeof(a));
for(int i = 1; i <= n; i++) a[i][i] = 0;
for(int i = 1; i <= m; i++) {
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
a[y][z] = a[x][y] = min(a[x][y], z);
}
//求最小生成树
prim();
for(int i = 2; i <= n; i++) ans += d[i];
cout << ans << endl;
}
4.dijkstra算法
int a[3010][3010], d[3010], n, m, ans;
bool v[3010];
void dijkstra(){
memset(d, 0x3f, sizeof(d)); //dist数组
memset(v, 0, sizeof(v)); //节点标记
d[1] = 0;
for(int i = 1; i < n; i++){ //重复进行n-1次
int x = 0;
//找到未标记节点中dist最小的
for (int j = 1; j <= n; j++)
if(!v[j] && (x == 0 || d[j] < d[x]))
x = j;
v[x] = 1;
//用全局最小值x更新其他节点
for(int y = 1; y <= n; y++)
if(!v[y])
d[y] = min(d[y], d[x] + a[x][y]);
}
}
int main(){
cin >> n >> m;
//构建邻接矩阵
memset(a, 0x3f, sizeof(a));
for(int i = 1; i <= n; i++) a[i][i] = 0;
for(int i = 1; i <= m; i++) {
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
a[x][y] = min(a[x][y], z);
}
//求单源最短路径 (抄的手累)
dijkstra();
for(int i = 1; i <= n; i++)
printf("%d\n", d[i]);
}
5.Floyd算法
int d[310][310], n, m;
int main(){
cin >> n >> m;
//把d数组初始化为邻接矩阵
memset(d, 0x3f, sizeof(d));
for (int i = 1; i <= n; i++) d[i][i] = 0;
for (int i = 1; i <= m; i++){
int x, y, z;
scanf("%d%d%d",&x,&y,&z);
d[x][y] = min(d[x][y], z);
}
//floyd求任意两点路径
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j =1; j<= n; j++)
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
//输出
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++) printf("%d ",d[i][j]);
puts("");
}
}
6.BST
(1)BST的建立
struct BST{
int l,r; //左右子节点在数组中的下标
int val; //节点关键码
} a[SIZE];//数组模拟链表
int tot, root, INF = 1<<30;
int New(int val) {
a[++tot].val = val;
return tot;
}
void Build() {
New(-INF),New(INF);
root = 1, a[1].r = 2;
}
(2)BST的检索
int Get(int p, int val){
if (p == 0) return 0; //检索失败
if (val == a[p].val) return p; //检索成功
return val < a[p].val ? Get(a[p].l, val) : Get(a[p].r, val);
}
(3)BST的插入
void Insert(int &p, int val){
if (p == 0) {
p = New(val); //p是引用,其父节点的r与l值会被同时更新
return;
}
if (val == a[p].val) return;
if (val < a[p].val) Insert(a[p].l, val);
else Insert(a[p].r, val);
}
(4)BST求前驱/后缀
int GetNext(int val){
int ans = 2; //a[2].val==INF
int p = root;
while(p){
if(val == a[p].val) {//检索成功 tired…
if(a[p].r > 0) {//有右子树
p = a[p].r;
//右子树上一直向左走
while (a[p].l > 0) p = a[p].l;
ans = p;
}
break;
}
//每经过一个节点都尝试更新后缀
if(a[p].val > val && a[p].val < a[ans].val) ans = p;
p = val < a[p].val ? a[p].l : a[p].r;
}
return ans;
}
(5)BST节点删除
void Remove(int val) {
//检索val,得到节点p
int &p = root;
while(p) {
if (val == a[p].val) break;
p = val < a[p].val ? a[p].l : a[p].r;
}
if(p == 0) return;
if (a[p].l == 0) { //没有左子树
p = a[p].r; //右子树代替p位置,注意p是引用
}
else if (a[p].r == 0){ //没有右子树
p = a[p].l; //左子树代替P位置,注意p是引用
}
else{//既有左子树又有右子树
//求后继结点
int next = a[p].r;
while(a[next].l > 0) next = a[next].l;
//next 一定没有左子树,直接删除
Remove(a[next].val);
//令节点next代替节点p的位置
a[next].l = a[p].l, a[next].r = a[p].r;
p = next; //p是引用
}
}
(6)Treap
void zig(int &p){//右旋
int q = a[p].l;
a[p].l = a[q].r, a[q].r = p;
p = q;//p是引用
}
void zag(int &p){//左旋
int q = a[p].r;
a[p].r = a[q].l, a[q].l = p;
p = q;
}
7.二分
(1)在单调递增序列a中查找>=x的数中最小的一个
while(l < r){
int mid = (l + r) >> 1;
if(a[mid] >= x) r = mid;
else l = mid + 1;
}
return a[l];
(2)在单调递增序列a中查找<=x的数中最大的一个
while(l < r){
int mid = (l + r + 1) >> 1;
if(a[mid] <= x) l = mid;
else r = mid - 1;
}
return a[l];
(3)二分答案
// 把n本书分成m组,每组厚度之和<=size,是否可行
bool valid(int size) {
int group = 1, rest = size;
for(int i = 1; i <= n; i++){
if (rest >= a[i]) rest -= a[i];
else group++, rest = size - a[i];
}
return group <= m;
}
int main(){
//二分答案,判断“每组厚度之和不超过二分的值”时
//能否在m组内把书分完
int l = 0, r = sum_of_ai;
while(l < r){
int mid = (l + r) / 2;
if (valid(mid)) r = mid;
else l = mid + 1;
}
cout << l << endl;
}
8.DFS
int c[20], cab[20], n, w, ans;
void dfs(int now, int cnt) {
if(cnt >= ans) return;
if(now == n + 1) {
ans = min(ans, cnt);
return;
}
for (int i = 1; i <= cnt; i++){//分配到已租用缆车
if (cab[i] + c[now] <= w) { //能装下
cab[i] += c[now];
dfs(now+1, cnt);
cab[i] -= c[now]; // 还原现场
}
}
cab[cnt +1] = c[now];
dfs(now + 1, cnt + 1);
cab[cnt + 1] = 0;
}
int main(){
cin >> n >> w;
for(int i = 1; i <= n; i++) cin >> c[i];
sort(c + 1, c + n + 1);
reverse(c + 1, c + n + 1);
ans = n; //最多用n辆缆车,每辆猫一辆
dfs(1,0);
cout << ans << endl;
}
9.0/1背包问题
int f[MAX_M+1];
memset(f, 0x3f, sizeof(f));
f[0] = 0;
for(int i = 1; i <= n; i++)
for(int j = m; j >= v[i]; j++)
f[j] = max(f[j], f[j-v[i]] + w[i]);
int ans = 0;
for(int j = 0; j <= m; j++)
ans = max(ans, f[j]);