Expedition
Code:
#include<iostream>
#include<queue>
using namespace std;
typedef priority_queue<int> q;
const int N = 10010;
int l,p,n;
int a[N], b[N];
int main()
{
cin >> n >> l >> p;
a[N] = { l };//把加油站视为终点
b[N] = { 0 };
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++)
cin >> b[i];
q heap;
heap.push(p);
int ans = -1, pos = 0, tank = 0;
for (int i = 1; i <= n; i++)
{
int d = a[i] - pos;
while (tank - d < 0)
{
if (heap.empty())
{
puts("-1");
return 0;
}
int t = heap.top();
heap.pop();
ans++;
//cout << t <<" "<<ans<< endl;
tank += t;
}
pos = a[i];
tank = tank - d;
heap.push(b[i]);
}
cout << ans << endl;
return 0;
}
使用优先队列解决问题
二叉搜索树的实现
Code:
#include<iostream>
using namespace std;
#define no NULL
struct node
{
int val;
node* lch, * rch;
};
//插入数值x
node* insert(node* p, int x)
{
if (p == NULL)
{
node* q = new node;
q->val = x;
q->lch = q->rch = NULL;
return q;
}
else
{
if (x < p->val) p->lch = insert(p->lch, x);
else p->rch = insert(p->rch, x);
return p;
}
}
//查找数值x
bool find(node* p, int x)
{
if (p == no) return false;
else if (x = p->val) return true;
else if (x < p->val) return find(p->lch, x);
else return find(p->rch, x);
}
//删除数值x
node* remove(node* p, int x)
{
if (p == NULL) return NULL;
else if (x < p->val) p->lch = remove(p->lch, x);
else if (x > p->val) p->rch = remove(p->rch, x);
else if (p->lch == NULL)
{
node* q = p->rch;
delete p;
return q;
}
else if (p->lch->rch == NULL)
{
node* q = p->lch;
q->rch = p->rch;
delete p;
return q;
}
else
{
node* q;
for (q = p->lch; q->rch->rch != NULL; q->rch);
node* r = q->rch;
q->rch = r->lch;
r->lch = p->lch;
r->rch = p->rch;
delete p;
return r;
}
return p;
}
int main()
{
//cout << y*4 << endl;
return 0;
}
并查集查找
食物链
每只动物i创建3个元素,分别代表i-A,i-B,i-C,用这3*N个元素建立并查集
- Code
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]);
else return x;
}
void unite(int x, int y)
{
x = find(x);
y = find(y);
if (x == y) return;
p[x] =y;
return;
}
int n, k;
int T[N], X[N], Y[X];
void solve()
{
init(N * 3);
int ans = 0;
for (int i = 0; i < k; i++)
{
int t = T[i];
int x = X[i] - 1,y=Y[i]-1;
if (x < 0 || x >= n || y < 0 || y >= n)
{
ans++;
continue;
}
if (t == 1)
{
if (same(x, y + N) || same(x, y + 2 * N)) ans++;
else
{
unite(x, y);
unite(x + N, y + N);
unite(x, 2 * N, y + 2 * N);
}
else
{
if (same(x, y) || same(x, y + 2 * N))
{
ans++;
}
else
{
unite(x, y + N);
unite(x + N, y + 2 * N);
unite(x + 2 * N, y);
}
}
}
}
}
如上图代码 es[i] = (edge){x[i],N+y[i],-d[i]}; 这里用N+y来使用并查集,这种方法用起来感觉很方便。大家可以试一下
后面会持续更新
3月29号更新,后续有时间会给代码加注释,而且有错误希望大家指正,我会尽快修改
图
没有圈的有向图叫做DAG(Directed Acyclic Graph)
- 如果把图中的顶点按照拓扑序从左到右排列,那么所有的边都是从左指向右的。因此,通过这样的编号方式,有些DAG问题就可以使用DP来解决了。求解拓扑序的算法叫做拓扑排序。
邻接表实现
//样例一
int h[N],e[N],ne[N],idx;
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
//样例二
struct edge
{
int to;
int cost;
}
vector<edge> G[MAX_V];
int V,E;
//从s向t连边
G[s].push_back(t);
//如果是无向图,则需要再从t向连s边
二分图判定
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int v, edgeCount;
int h[N], e[N], ne[N], idx = 0;
int color[N];
//用1,2表示不同颜色
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
bool dfs(int u, int x)
{
color[u] = x;
for (int i = h[u];i != -1; i = ne[i])
{
int val = e[i];
if (color[val] == color[u]) return false;
if (!color[val])
{
if (!dfs(val, 3 - x)) return false;
}
}
return true;
}
void solve()
{
memset(h, -1, sizeof h);
cin >> v >> edgeCount; // 点是从0开始
for (int i = 0; i < edgeCount; i++)
{
int a, b;
cin >> a >> b;
add(a, b);
add(b, a);
}
for (int i = 1; i <= v; i++)
{
if (!color[i])
{
if (!dfs(i, 1))
{
cout << "No" << endl;
return;
}
}
}
cout << "Yes" << endl;
}
int main()
{
std::ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
solve();
return 0;
}
单源最短路问题1(Bellman-Ford算法)
- 题目:
#include<iostream>
#include<algorithm>
using namespace std;
// 定义边的结构体,包括起点from,终点to,以及边的权值val
struct Edge {
int from, to, val;
};
const int N = 10010; // 定义最大边数
const int INF = 1e9; // 定义一个足够大的数表示无穷大
Edge es[N]; // 存储边的数组
int d[N]; // 存储最短距离的数组
int v, e; // v表示顶点数,e表示边数
// 添加边的函数
void add(int a, int b, int c, int idx) {
es[idx].from = a;
es[idx].to = b;
es[idx].val = c;
}
// Bellman-Ford算法实现计算最短路径
void shortest_path(int s) {
for (int i = 0; i < v; i++) d[i] = INF; // 初始化所有距离为无穷大
d[s] = 0; // 起始点到自己的距离为0
// 进行松弛操作
while (true) {
bool update = false; // 标记本轮是否有更新
for (int i = 0; i < e; i++) { // 遍历所有的边
Edge e1 = es[i];
// 如果起点的最短距离不是无穷大,并且通过这条边可以使得终点的距离更短,则更新终点的最短距离
if (d[e1.from] != INF && d[e1.to] > d[e1.from] + e1.val) {
d[e1.to] = d[e1.from] + e1.val;
update = true; // 发生了更新
}
}
if (!update) break; // 如果这一轮没有任何更新,说明已经找到了所有最短路径,退出循环
}
}
// 读取输入并添加边
void solve() {
cin >> v >> e; // 输入顶点数和边的数目
for (int i = 0; i < e; i++) {
int a, b, c; // 输入边的起点,终点和权值
cin >> a >> b >> c;
add(a, b, c, i); // 添加边
}
shortest_path(0);
}
int main() {
cin >> v >> e; // 输入顶点数和边数
solve(); // 调用solve函数处理输入的边
return 0;
}
这里要想明白为什么while循环最对执行|v|-1次,最好是画一个图
堆优化dijkstra
priority_queue<PII,vector<PII>,greater<PII>> heap;
Floyd-Warshall算法
int d[MAX_V][MAX_V]; //d[u][v]表示边e=(u,v)的权值(不存在时设为INF,不过d[i][j]=0)
int v;//顶点数
void warshall_floyd()
{
for(int k=0;k<v;k++)
for(int i=0;i<v;i++)
for (int j = 0; j < v; j++)
{
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);//优化成二维数组
}
}
路径还原
很好的想法,用一个前驱数组解决