每天遇到的奇妙方法集合
1. 摩尔投票法
自从上次 redbag
用加法好好的***难过了 yyy
同学以后,yyy
十分愤怒。
他还击给了 redbag
一题,但是这题他惊讶的发现自己居然也不会,所以只好找你
一共有 个正整数 ,他让 redbag
找众数。他还特意表示,这个众数出现次数超过了一半。
摩尔投票法的基本思想很简单,在每一轮投票过程中,从数组中找出一对不同的元素,将其从数组中删除。这样不断的删除直到无法再进行投票,如果数组为空,则没有任何元素出现的次数超过该数组长度的一半。如果只存在一种元素,那么这个元素则可能为目标元素。
为了便于理解,我们想象一个情景,有一堆人在打架,我们假设每一个人的战斗力都是 换 。也就是 打死 , 也会死。
假设只有 波人(我们把不是众数的数字看作一个数)且各占二分之一,显然继续打下去两边人都会死光。
但是我们现在有 波人,其中一波人特别多(一半以上),显然这波人必然是赢家,虽然不知道打完还剩几个,但一定会有剩下的。因为一换一。若第二波人有x个,则第一波人有()个且 。那么最后剩下的人就是 个。假设这 波人头上顶着 个不同的数字,这个剩下的人的数字就是众数。
以上用于帮助理解代码。
所以我们可以把摩尔投票法看作一种抵消的思想,当前数字进场,然后和上一个判断,如果是同一个数计数器,如果不是计数器。
当计数器等于 时, 重新登记为新输入的数,进行抵消的操作,最后剩下的一定是众数(但众数必须满足大于总数的一半)。
#include <bits/stdc++.h>
using namespace std;
int n, x, ans, y = 0;
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%d", &x);
if (y == 0)
ans = x;
if (ans == x)
y++;
if (ans != x)
y--;
}
printf("%d", ans);
return 0;
}
2. 全源最短路
Johnson
全源最短路
-
建立一个虚点 号结点。
-
从 号结点向 连接一条权值为 的有向边。
-
使用
spfa
算法求出从 号结点到 的最短路 。 -
由于
dijkstra
不能求负权最短路,所以将连接 的边权 更新为 。 -
接下来对 号点进行
dijkstra
,统计答案即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define int ll
const int N = 16666;
const int inf = 1e9;
struct Edge
{
int nxt;
int to;
int w;
} e[N];
int head[N], edge_num = 0;
inline void add_edge(int x, int y, int z)
{
e[++edge_num].to = y;
e[edge_num].nxt = head[x];
e[edge_num].w = z;
head[x] = edge_num;
}
int n, m, indeg[N], inque[N];
int d[N];
inline bool SPFA(int s)
{
for (int i = 1; i <= n; i++)
{
d[i] = inf;
}
memset(inque, false, sizeof(inque));
queue<int> qwq;
qwq.push(s);
d[s] = 0, inque[s] = true;
indeg[s]++;
while (!qwq.empty())
{
int u = qwq.front();
qwq.pop();
inque[u] = false;
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to;
if (d[v] > d[u] + e[i].w)
{
d[v] = d[u] + e[i].w;
if (inque[v] == false)
{
qwq.push(v);
inque[v] = true;
indeg[v]++;
if (indeg[v] >= n + 1)
{
return true;
}
}
}
}
}
return false;
}
int dis[N];
bool vis[N];
inline void Dij(int s)
{
for (int i = 1; i <= n; i++)
{
dis[i] = inf;
}
memset(vis, false, sizeof(vis));
priority_queue<pii, vector<pii>, greater<pii>> q;
dis[s] = 0;
q.push(make_pair(0, s));
while (!q.empty())
{
int u = q.top().second;
q.pop();
if (vis[u])
{
continue;
}
vis[u] = true;
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to;
if (dis[v] > dis[u] + e[i].w)
{
dis[v] = dis[u] + e[i].w;
if (vis[v] == false)
{
q.push(make_pair(dis[v], v));
}
}
}
}
}
signed main()
{
scanf("%lld%lld", &n, &m);
for (int i = 1, x, y, z; i <= m; i++)
{
scanf("%lld%lld%lld", &x, &y, &z);
add_edge(x, y, z);
}
for (int i = 1; i <= n; i++)
{
add_edge(0, i, 0);
}
if (SPFA(0) == true)
{
printf("-1");
return 0;
}
for (int i = 1; i <= n; i++)
{
for (int j = head[i]; j; j = e[j].nxt)
{
int v = e[j].to;
e[j].w += d[i] - d[v];
}
}
for (int i = 1; i <= n; i++)
{
Dij(i);
ll ans = 0;
for (int j = 1; j <= n; j++)
{
if (dis[j] == inf)
{
ans += 1ll * inf * j;
}
else
{
ans += 1ll * j * (dis[j] - d[i] + d[j]);
}
}
printf("%lld\n", ans);
}
return 0;
}
树
树的边权和等于第 个叶子到第 个叶子的距离(简单路径的长度)之和(特别的,第 个叶子是第 个)除以 。
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18122130
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话