Day 1:4273. 链表合并
关键词:链表
题意:给定两个链表的首地址和 n 个结点,求合并后的链表,合并规则:从头每添加长链表中两个结点就要从锻炼表的末尾开始添加一个结点
图示:
思路:除非是面试中(你面前坐了一个面试官)链表题要真用链表来写,否则一般我们都用数组来对链表进行模拟,本题用 Vector 结合 Pair 存放每个结点的地址和数据,循环遍历进行合并,注意题目中未明确 a 链表一定是长链表,所以要判断进行交换
AC代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
const int N = 100010;
int h1, h2, n; //h1,h2分别为头地址, n为结点数
//数组模拟链表
int v[N], ne[N]; //v[i] 存放 i 地址的结点的数据, ne[i] 存放 i 地址的结点的下一个结点地址
vector<PII> a,b; //两个链表
int main( )
{
cin >> h1 >> h2 >> n;
//输入n个结点
while(n --)
{
int adr, val, next; //地址、数据、下一结点地址
cin >> adr >> val >> next;
v[adr] = val;
ne[adr] = next;
}
//输入两个链表
for(int i = h1; i != -1; i = ne[i]) a.push_back({i, v[i]});
for(int i = h2; i != -1; i = ne[i]) b.push_back({i, v[i]});
//保证a为长的链表
if(a.size() < b.size()) swap(a, b);
vector<PII> c; //合并后链表
//合并链表
for(int i = 0, j = b.size() - 1; i < a.size(); i += 2, j --)
{
c.push_back(a[i]);
if(i + 1 < a.size()) c.push_back(a[i + 1]);
if(j >= 0) c.push_back(b[j]);
}
for(int i = 0; i < c.size(); i ++)
{
if(i + 1 < c.size())
printf("%05d %d %05d\n", c[i].x, c[i].y, c[i + 1].x);
else
printf("%05d %d -1\n", c[i].x, c[i].y);
}
return 0;
}
Day 2 :4274. 后缀表达式
关键词:树的遍历
题意:给定几个结点组成一棵树,求其后缀表达式(后序遍历)
思路:用数组模拟树,首先要找到哪个是根结点,接着对根结点进行遍历,遍历分三种情况:
(1)存在左右子树:后序遍历,先左再右后根
(2)不存在左右子树,即当前结点为叶子结点:直接根
(3)只存在右结点,即当前结点为负号:先序遍历,先根再右
AC代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 25;
int n; //结点数
//数组模拟树
string v[N];
int l[N],r[N];
bool st[N]; //判断结点是否有父结点
void dfs(int u)
{
cout << '(';
if (l[u] != -1 && r[u] != -1) //若左右儿子都不为空,后序遍历
{
dfs(l[u]);
dfs(r[u]);
cout << v[u];
}
else if (l[u] == -1 && r[u] == -1) //若左右儿子为空,即该结点为叶子
{
cout << v[u];
}
else //左儿子为空,右儿子不为空,先序遍历
{
cout << v[u];
dfs(r[u]);
}
cout << ')';
}
int main( )
{
cin >> n;
int data,left,right;
for (int i = 1; i <= n; i ++)
{
cin >> v[i] >> l[i] >> r[i] ; //输入i号结点的数据域,左儿子和右儿子
if (left != -1 ) st[l[i]] = true;
if (right != -1) st[r[i]] = true;
}
int root;
//寻找根节点,即没有父结点的结点
for (int i = 1; i <= n; i ++)
if (st[i] == false)
root = i;
dfs(root); //深搜
return 0;
}
Day 3:4275.Dijkstra序列
关键词:Dijkstra算法
题意:给定一个图和一个序列,判断求这个序列是否是Dijkstra序列。
思路:Dijkstra算法,找到一个尚未在集合内且与源顶点距离最小的顶点去判断
AC代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010, INF = 0x3f3f3f3f;
int n, m;
int dist[N], g[N][N];
bool st[N];
int q[N];
bool dijkstra()
{
memset(dist, 0x3f, sizeof dist);
memset(st, 0, sizeof st);
dist[q[0]] = 0;
for (int i = 0; i < n; i ++)
{
int t = q[i];
for (int j = 1; j <= n; j++)
if (!st[j] && dist[j] < dist[t])
return false;
st[t] = true;
for (int j = 1; j <= n; j ++)
dist[j] = min(dist[j], dist[t] + g[t][j]);
}
return true;
}
int main( )
{
cin >> n >> m;
memset(g, 0x3f, sizeof g);
while (m --)
{
int a, b, c;
cin >> a >> b >> c;
g[a][b] = g[b][a] = c;
}
int k;
cin >> k;
while (k --)
{
for (int i = 0; i < n; i ++) cin >> q[i];
if (dijkstra())
puts("Yes");
else
puts("No");
}
return 0;
}