目录
1、BFS(广搜)模板题
涂色问题——代码如下:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 205;
int dian, bian;
vector <vector<int> > v;
int colour[maxn];
bool bfs() {
queue<int> que;
que.push(0);
colour[0] = 1;
while(que.size()) {
int a = que.front();
que.pop();
for(int i = 0; i < v[a].size(); i++) {
int j = v[a][i];
if(colour[j] == colour[a]) return false;
if(colour[j] == 0) {
colour[j] = colour[a] * -1;
que.push(j);
}
}
}
return true;
}
int main() {
while(cin >> dian >> bian && dian) {
v.clear();
v.resize(dian, vector<int>() );
fill(colour, colour + maxn, 0);
for(int i = 0; i < bian; i++) {
int x, y;
cin >> x >> y;
v[x].push_back(y);
v[y].push_back(x);
}
if(bfs()) cout << "BICOLORABLE." << endl;
else cout << "NOT BICOLORABLE." << endl;
}
return 0;
}
蓝桥杯国赛,扩散——代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N = 10000;
long long ans;
int a[N][N], hy[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
struct node{
int x, y, st;
}s, t;
void bfs(){
int i;
queue<node> q;
q.push((node){0 + 2100, 0 + 2100, 0});
q.push((node){2020 + 2100, 11 + 2100, 0});
q.push((node){11 + 2100, 14 + 2100, 0});
q.push((node){2000 + 2100, 2000 + 2100, 0});
a[0 + 2100][0 + 2100] = a[2020 + 2100][11 + 2100] = a[11 + 2100][14 + 2100] = a[2000 + 2100][2000 + 2100] = 1;
ans = 4;
while(q.size()){
t = q.front();
q.pop();
s.st = t.st + 1;
for(int i = 0; i < 4; i++){
s.x = t.x + hy[i][0];
s.y = t.y + hy[i][1];
if(a[s.x][s.y] == 0 && s.st <= 2020){
a[s.x][s.y] = 1;
ans++;
q.push(s);
}
}
}
cout << ans;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
bfs();
return 0;
}
2、DFS(深搜)模板题
油井问题——代码如下:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1007;
int m, n, dx, dy, ans;
char map1[maxn][maxn];
int xx[8] = {1, 1, 1, 0, -1, -1, -1 , 0}, yy[8] = {-1, 0, 1, 1, 1, 0, -1, -1};
void dfs(int x, int y) {
map1[x][y] = '*';
for(int i = 0; i < 8; i++) {
dx = x + xx[i];
dy = y + yy[i];
if(dx >= 1 && dx <= m && dy >= 1 && dy <= n && map1[dx][dy] == '@') dfs(dx, dy);
}
return ;
}
void solve() {
ans = 0;
for(int i = 1; i <= m; i++)
for(int j = 1; j <= n; j++)
if(map1[i][j] == '@') {
dfs(i, j);
ans++;
}
}
int main() {
while(cin >> m >> n && m && n) {
for(int i = 1; i <= m; i++)
for(int j = 1; j <= n; j++)
cin >> map1[i][j];
solve();
cout << ans << endl;
}
return 0;
}
3、Dijstra(单源最短路径)模板题
优先队列优化——代码如下:
#include<bits/stdc++.h>
#include<functional>
using namespace std;
typedef pair<int, int> P;
vector<vector<P > > v;
int n, m, s, d;
int cnt[505], dis[505], last[505], curSum[505], path[505];
bool vis[505];
void dijkstra() {
for(int i = 0; i < 505; i++) {
dis[i] = INT_MAX >> 1;
vis[i] = false;
last[i] = -1;
curSum[i] = cnt[i];
path[i] = 1;
}
dis[s] = 0;
priority_queue<P, vector<P>, greater<P> > q;
q.push(make_pair(0, s));
while(q.size()) {
P e = q.top();
q.pop();
int z = e.first, y = e.second;
if(vis[y] == true) continue;
vis[y] = true;
for(int i = 0; i < v[y].size(); i++) {
int x = v[y][i].second, z = v[y][i].first;
if(dis[y] + z < dis[x]) {
curSum[x] = curSum[y] + cnt[x];
dis[x] = dis[y] + z;
last[x] = y;
q.push(make_pair(dis[x], x));
path[x] = path[y];
} else if(dis[x] == dis[y] + z) {
path[x] = path[x] + path[y];
if(curSum[x] < curSum[y] + cnt[x]) {
curSum[x] = curSum[y] + cnt[x];
last[x] = y;
q.push(make_pair(dis[x], x));
}
}
}
}
}
int main() {
cin >> n >> m >> s >> d;
for(int i = 0; i < n; i++) cin >> cnt[i];
v.resize(n);
for(int i = 0; i < m; i++) {
int x, y, z;
cin >> x >> y >> z;
v[x].push_back(make_pair(z, y));
v[y].push_back(make_pair(z, x));
}
dijkstra();
cout << path[d] << " " << curSum[d] << endl;
vector<int > ans;
int g = d;
while(g != -1) {
ans.push_back(g);
g = last[g];
}
for(int i = ans.size() - 1; i >= 0; i--) {
if(i < ans.size() - 1) cout << " ";
cout << ans[i];
}
return 0;
}
朴素算法——代码如下:
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 1007;
const int inf = 1<<30;
int n, m, s, g[maxn][maxn];//n点数,m边数,s起始位置
int d[maxn];
bool vis[maxn] = {false};
void dijsktra() {
s = 1;
fill(d, d + maxn, inf);
d[s] = 0;
for(int i = 0; i < n; i++) {
int u = -1, min = inf;
for(int j = 1; j <= n; j++) {
if(vis[j] == false && d[j] < min) {
u = j;
min = d[j];
}
}
if(u == -1) continue;
vis[u] = true;
for(int v = 1; v <= n; v++) {
if(vis[v] == false && g[u][v] != inf && d[u] + g[u][v] < d[v]) {
d[v] = d[u] + g[u][v];
}
}
}
}
int main() {
int u, v, w;
cin >> m >> n;
fill(g[0], g[0] + maxn * maxn, inf);
for(int i = 0; i < m; i++) {
cin >> u >> v >> w;
g[u][v] = g[v][u] = min(g[u][v],w);
}
dijsktra();
cout << d[n] << endl;
return 0;
}
天梯赛,网红景点——代码如下:
#include<bits/stdc++.h>
using namespace std;
int mp[205][205], vis[205];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n, m;
cin >> n >> m;
for(int i = 0; i < m; i++){
int x, y, z;
cin >> x >> y >> z;
mp[x][y] = mp[y][x] = z;
}
int k, l, cnt = 0, no, ans = 1e9 + 2;
cin >> k;
for(int i = 1; i <= k; i++){
cin >> l;
int f = 0, sum = 0, last = 0, ct = 0;
fill(vis, vis + 205, 0);
for(int j = 0; j < l; j++){
int t;
cin >> t;
if(vis[t] == 1) f = 1;
vis[t] = 1;
if(mp[last][t] == 0) f = 1;
sum += mp[last][t];
last = t;
ct++;
}
if(mp[last][0] == 0) f = 1;
if(ct != n) f = 1;
if(f == 1) continue;
cnt++;
sum += mp[last][0];
if(sum < ans){
ans = sum;
no = i;
}
}
cout << cnt << endl << no << " " << ans;
return 0;
}
天梯赛练习L3-直捣黄龙——代码如下:
#include<bits/stdc++.h>
using namespace std;
const int Inf = 9999999;
const int o = 205;
int graph[o][o];
bool vis[o];//标记路径
int dist[o];//存最短路径
int path[o];//存路径
int kill[o];//存杀敌数
int node[o];//存经过的城市数量
int army[o];//各城市的士兵
int road[o];//最短路径的数量
int n;
map<string, int> M;
map<int, string> N;
void Dijkstra(int sta, int end) {
memset(vis, 0, sizeof(vis));
memset(dist, Inf, sizeof(dist));
memset(path, -1, sizeof(path));
memset(kill, 0, sizeof(kill));
memset(node, 0, sizeof(node));
memset(road, 0, sizeof(road));
vis[sta] = true;
dist[sta] = 0;
for(int i = 0; i < n; i++) {
if(!vis[i] && graph[sta][i]) {
dist[i] = graph[sta][i];
node[i] = 1;
kill[i] = army[i];
path[i] = sta;
road[i] = 1;
}
}
while(1) {
int minn = Inf, v = sta;
for(int i = 0; i < n; i++) {
if(!vis[i] && dist[i] < minn) {
minn = dist[i];
v = i;
}
}
if(v == end) break;
vis[v] = true;
for(int i = 0; i < n; i++) {
if(!vis[i] && graph[v][i] + minn <= dist[i]) {
if(graph[v][i] + minn < dist[i]) {
dist[i] = graph[v][i] + minn;
node[i] = node[v] + 1;
kill[i] = kill[v] + army[i];
path[i] = v;
road[i] = road[v];
} else {
road[i] += road[v];
if(node[v] + 1 >= node[i]) {
if(node[v] + 1 > node[i]) {
kill[i] = kill[v] + army[i];
node[i] = node[v] + 1;
path[i] = v;
} else {
if(kill[v] + army[i] > kill[i]) {
kill[i] = kill[v] + army[i];
path[i] = v;
}
}
}
}
}
}
}
}
void find(int x) {
if(path[x] != -1) {
find(path[x]);
cout << N[path[x]] << "->";
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int i, m;
string s, e;
cin >> n >> m >> s >> e;
M[s] = 0;
N[0] = s;
army[0] = 0;
string str;
for(int i = 1; i < n; i++) {
cin >> str >> army[i];
M[str] = i;
N[i] = str;
}
string x, y;
int w;
memset(graph, Inf, sizeof(graph));
for(int i = 0; i < m; i++) {
cin >> x >> y >> w;
graph[M[x]][M[y]] = w;
graph[M[y]][M[x]] = w;
}
Dijkstra(M[s], M[e]);
find(M[e]);
cout << e << endl;
printf("%d %d %d", road[M[e]], dist[M[e]], kill[M[e]]);
return 0;
}
4、Floyd(多源最短路径)模板题
3for算法,带记录路径——代码如下:
#include<bits/stdc++.h>
using namespace std;
const int inf = 1<<29;
int num[505], dis[505][505], res[505][505];
int N, M, S, D, ans;
int floy(){
for(int k = 0; k < N; k++){
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++){
if(dis[i][k] != inf && dis[k][j] != inf && dis[i][k] + dis[k][j] <= dis[i][j] && num[i] + num[k] + num[j] > num[i] + num[j]){
dis[i][j] = dis[i][k] + dis[k][j];
res[i][j] = res[i][k];
}
}
}
}
return 0;
}
int main(){
fill(dis[0], dis[0] + 505 * 505, inf);
cin >> N >> M >> S >> D;
for(int i = 0; i < N; i++) cin >> num[i];
for(int i = 0; i < M; i++){
int x, y, z;
cin >> x >> y >> z;
dis[x][y] = dis[y][x] = z;
res[x][y] = y;
res[y][x] = x;
}
floy();
int f = S, g = D, cnt = 0;
ans = num[g];
while(f != g){
ans = ans + num[f];
cnt++;
if(g == res[f][g]) break;
f = res[f][g];
}
cout << cnt << " " << ans << endl;
f = S, g = D;
cout << f;
while(f != g){
cout << " " << res[f][g];
if(g == res[f][g]) break;
f = res[f][g];
}
return 0;
}
5、链表操作
链表去重——代码如下:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5;
struct Node {
int address;
int data;
int next;
int num = maxn * 2;
} node[maxn];
bool vis[maxn];
bool cmp(Node a, Node b) {
return a.num < b.num;
}
int main() {
int head, n, x, c, c1 = 0, c2 = 0;
cin >> head >> n;
for(int i = 0; i < n; i++) {
cin >> x;
cin >> node[x].data >> node[x].next;
node[x].address = x;
}
for(int i = head; i != -1; i = node[i].next) {
if(!vis[abs(node[i].data)]) {
vis[abs(node[i].data)] = true;
node[i].num = c1++;
}
else node[i].num = maxn + c2++;
}
sort(node, node + maxn, cmp);
c = c1 + c2;
for(int i = 0; i < c; i++) {
if(i != c1 - 1 && i != c - 1) printf("%05d %d %05d\n", node[i].address, node[i].data, node[i + 1].address);
else printf("%05d %d -1\n", node[i].address, node[i].data);
}
return 0;
}
反转链表——代码如下:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int main(){
int first, n, k, temp;
int next[maxn], data[maxn], list[maxn];
cin >> first >> n >> k;
for(int i = 0; i < n; i++){
cin >> temp;
cin >> data[temp] >> next[temp];
}
int sum = 0;
while(first != -1){
list[sum++] = first;
first = next[first];
}
for(int i = 0; i < sum - (sum % k); i += k){
reverse(begin(list) + i, begin(list) + i + k);
}
for(int i = 0; i < sum - 1; i++){
printf("%05d %d %05d\n", list[i], data[list[i]], list[i+1]);
}
printf("%05d %d -1", list[sum - 1], data[list[sum - 1]]);
return 0;
}
6、栈的运用
取栈的top时需要判断栈是否为空,不然会报错!
出栈顺序合法性——代码如下:
#include<bits/stdc++.h>
using namespace std;
stack<int> s;
queue<int> q;
int main(){
int m, n, k;
cin >> m >> n >> k;
while(k--){
while(!s.empty()) s.pop();
while(!q.empty()) q.pop();
for(int i = 0; i < n; i++){
int x;
cin >> x;
q.push(x);
}
int num = 1;
while(!q.empty() && s.size() < m){
s.push(num);
num++;
while(!s.empty() && !q.empty() && s.top() == q.front()){
s.pop();
q.pop();
}
if(num == n + 1) break;
}
if(num == n + 1 && s.empty()) cout << "YES\n";
else cout << "NO\n";
}
return 0;
}
7、树
二叉搜索树
二叉搜索树建树和结点统计——代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int l[N], r[N], w[N], id, cnt[N], ma;
//l,r为左右儿子,w是结点权值,cnt记录每层的结点数,ma是最深深度
void build(int &x, int ww) {//建立二叉搜索树
if(!x) {
x = ++id;
w[x] = ww;
} else {
if(ww <= w[x]) build(l[x], ww);
else build(r[x], ww);
}
}
void dfs(int x, int depth) {
if(!x) return;
cnt[depth]++;
ma = max(ma, depth);//ma为最深深度
dfs(l[x], depth + 1);
dfs(r[x], depth + 1);
}
int main() {
int n, rt = 0;
cin >> n;
for(int i = 0; i < n; i++) {
int xx;
cin >> xx;
build(rt, xx);
}
dfs(rt, 0);
cout << cnt[ma] + cnt[ma - 1] << endl;
return 0;
}
完全二叉树的三种遍历
前序,中序,后序——代码如下:
//完全二叉树的三种遍历建树
#include<bits/stdc++.h>
using namespace std;
int a[1000], tree[1000];
int n, cnt;
void dfs(int u){
if(u > n) return;
int lson = 2 * u;
int rson = 2 * u + 1;
/*前序遍历建树 (从顶开始,先所有左边,然后再右)
tree[u] = a[++cnt];
dfs(lson);
dfs(rson);
*/
/*中序遍历建树 (从最左开始,左中右)
dfs(lson);
tree[u] = a[++cnt];
dfs(rson);
*/
/*前序遍历建树 (从最左开始,左右中)
dfs(lson);
dfs(rson);
tree[u] = a[++cnt];
*/
}
int main(){
ios::sync_with_stdio(false);
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
dfs(1);
//按照层序遍历输出
for(int i = 1; i <= n; i++) printf("%d ", tree[i]);
return 0;
}
8、并查集
并查集就是最左最大和最右最大两种形式找大哥,每个集团只有一个大哥,大哥的编号就是本人,小弟的编号都为集团的大哥的编号,最后看有多少个大哥就是有多少集团。
天梯赛,部落——代码如下:
#include<bits/stdc++.h>
using namespace std;
int m, x, y, sum, n, cnt, k, f[10005], a[10005], b[10005];
int num;
int boss(int x) {
if(f[x] == x) return x;
else {
f[x] = boss(f[x]);
return(boss(f[x]));
}
}
int main() {
cin >> n;
for(int i = 0; i < n; i++) {
cin >> k;
for(int j = 0; j < k; j++) {
cin >> a[j];
if(f[a[j]] == 0) {
f[a[j]] = a[j];
b[cnt++] = a[j];
}
}
for(int j = 1; j < k; j++){
f[boss(a[j])] = boss(a[0]);
num++;
}
}
cout << cnt << " " << cnt - num << endl;
cin >> m;
for(int i = 0; i < m; i++) {
cin >> x >> y;
if(boss(x) != boss(y)) cout << "N\n";
else cout << "Y\n";
}
return 0;
}
总结
对于算法模板熟练套用才能加快做题的节奏。