堆优化的DIJ单源最短路:
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
using namespace std;
int read(){
int x,f;
x=0;f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int n,m,s;
struct bnode{
int cd;
int v;
};
vector<bnode> dt[100009];
int bj[100009]={0};
int dis[100009]={0};
struct node{
int xh;
int dx;
};
struct cmp{
bool operator() (node a,node b){
return a.dx>b.dx;
}
};
priority_queue<node,vector<node>,cmp> pp;
int main(){
n=read();m=read();s=read();
int ma,mb,mv;
for(int i=1;i<=m;i++){
ma=read();mb=read();mv=read();
bnode tmp;
tmp.cd=mb;tmp.v=mv;
dt[ma].push_back(tmp);
}
for(int i=0;i<sizeof(dis)/4;i++){
dis[i]=0x7fffffff;
}
dis[s]=0;
pp.push((node){s,0});
while(!pp.empty()){
node tmp=pp.top();
pp.pop();
if(bj[tmp.xh]==1)continue;
bj[tmp.xh]=1;
for(int i=0;i<dt[tmp.xh].size();i++){
if(bj[dt[tmp.xh][i].cd]==0&&dis[dt[tmp.xh][i].cd]>dis[tmp.xh]+dt[tmp.xh][i].v){
// cout<<dis[dt[tmp.xh][i].cd]<<" "<<dis[tmp.xh]+dt[tmp.xh][i].v<<endl;
dis[dt[tmp.xh][i].cd]=dis[tmp.xh]+dt[tmp.xh][i].v;//更新距离
pp.push((node){dt[tmp.xh][i].cd,dis[dt[tmp.xh][i].cd]});//放进堆中;
}
}
}
for(int i=1;i<=n;i++){
cout<<dis[i]<<" ";
}
return 0;
}
两个坑点:
①优先队列的结构体重定义排序,排序函数的规则和sort的规则相反,需要变一下。
②大数据量加快读
堆优化的SPFA单源最短路:
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
using namespace std;
int read(){
int x,f;
x=0;f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int n,m,s;
struct bnode{
int cd;
int v;
};
vector<bnode> dt[100009];
int bj[100009]={0};
int dis[100009]={0};
struct node{
int xh;
int dx;
};
struct cmp{
bool operator() (node a,node b){
return a.dx>b.dx;
}
};
priority_queue<node,vector<node>,cmp> pp;
int main(){
n=read();m=read();s=read();
int ma,mb,mv;
for(int i=1;i<=m;i++){
ma=read();mb=read();mv=read();
bnode tmp;
tmp.cd=mb;tmp.v=mv;
dt[ma].push_back(tmp);
}
for(int i=0;i<sizeof(dis)/4;i++){
dis[i]=0x7fffffff;
}
dis[s]=0;
bj[s]=1;
pp.push((node){s,0});
while(!pp.empty()){
node tmp=pp.top();
pp.pop();
// if(bj[tmp.xh]==1)continue;
bj[tmp.xh]=0;
for(int i=0;i<dt[tmp.xh].size();i++){
if(dis[dt[tmp.xh][i].cd]>dis[tmp.xh]+dt[tmp.xh][i].v){
// cout<<dis[dt[tmp.xh][i].cd]<<" "<<dis[tmp.xh]+dt[tmp.xh][i].v<<endl;
dis[dt[tmp.xh][i].cd]=dis[tmp.xh]+dt[tmp.xh][i].v;//更新距离
if(bj[dt[tmp.xh][i].cd]!=1)
pp.push((node){dt[tmp.xh][i].cd,dis[dt[tmp.xh][i].cd]});//放进堆中;
}
}
}
for(int i=1;i<=n;i++){
cout<<dis[i]<<" ";
}
return 0;
}
注意:
①堆优化的spfa和dij很相似,代码重合度为98%,只是dij出队后不会再次入队,但是spfa出队后会再次入队。
②spfa可以用来求单源最长路,但是dij不可以。
单源最短路模板DIJ:
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
int n,m,s;
int read(){
int x,f;
x=0;f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int bj[10009]={0};
int dis[10009]={0};
struct bian{
int cd;
int val;
};
vector<bian> dt[10009];
int getwz(){
int minn=0x7fffffff;
int minwz;
for(int i=1;i<=n;i++){
if(bj[i]==0&&dis[i]<minn){
minn=dis[i];
minwz=i;
}
}
return minwz;
}
int main(){
n=read();
m=read();
s=read();
int ma,mb,mc;
for(int i=1;i<=m;i++){
ma=read();mb=read();mc=read();
dt[ma].push_back((bian){mb,mc});
}
for(int i=0;i<=n;i++){
dis[i]=0x7fffffff;
}
dis[s]=0;
for(int i=1;i<n;i++){
int wz=getwz();
bj[wz]=1;
for(int j=0;j<dt[wz].size();j++){
// cout<<dt[wz][j].cd<<" "<<bj[dt[wz][j].cd]<<" "<<dis[dt[wz][j].cd]<<" "<<dis[wz]<<" "<<dt[wz][j].val<<endl;
if(bj[dt[wz][j].cd]==0&&dis[dt[wz][j].cd]>dis[wz]+dt[wz][j].val){
dis[dt[wz][j].cd]=dis[wz]+dt[wz][j].val;
}
}
}
int sum=0;
for(int i=1;i<=n;i++){
cout<<dis[i]<<" ";
}
return 0;
}
FLOYD:多元最短路
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
int n,m;
int read(){
int x,f;
x=0;f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int dp[1009][1009]={0};
int main(){
n=read();
m=read();
int ma,mb,mc;
for(int i=0;i<=n;i++){
for(int j=0;j<=n;j++){
dp[i][j]=100009;
}
dp[i][i]=0;
}
for(int i=1;i<=m;i++){
ma=read();mb=read();mc=read();
if(dp[ma][mb]>mc)
dp[ma][mb]=mc;
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(dp[i][j]>dp[i][k]+dp[k][j])
dp[i][j]=dp[i][k]+dp[k][j];
}
}
}
return 0;
}
坑点:
①dp数组的初始值一定要赋值成比最长边还要大的数字,但是如果赋值成0x7fffffff,会导致任意两个不存在的边相加后溢出int范围变成负数,得到负边,所以初始值尽量保证两个初始值相加不超过int
②没边的赋值成最大值,有边的赋值成边权值即可。
最短路题型:如果要求所有点到任意一点的最短路,可以反向建图,再从单点跑一遍最短路即可。
堆排序:
#include<iostream>
#include<cstdio>
using namespace std;
int n;
int sz[1009]={0};
void jh(int wz){
if(wz>n/2)return;
int jl;
if(sz[2*wz]>sz[2*wz+1])jl=2*wz;
else jl=2*wz+1;
if(sz[wz]<sz[jl]){
swap(sz[jl],sz[wz]);
jh(jl);
}
}
void gz(){
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>sz[i];
}
for(int i=n/2;i>=1;i--){
jh(i);
}
for(int i=1;i<=n;i++){
cout<<sz[1]<<" ";
swap(sz[1],sz[n-i+1]);
sz[n-i+1]=0;
jh(1);
}
return 0;
}
堆排序:核心代码是jh函数,交换函数,将堆中以wz为根的堆重新构造堆;
线性筛素数:
#include<iostream>
#include<cstdio>
using namespace std;
int n,q;
int read(){
int x,f;
x=0;f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int ss[100000009]={0};
int dj[100000009]={0};
int main(){
n=read();
q=read();
ss[0]=1;
ss[1]=1;
int sum=0;
for(int i=2;i<=n;i++){
if(ss[i]==0)dj[++sum]=i;
for(int j=1;j<=sum&&(long long)i*j<=n;j++){
ss[dj[j]*i]=1;
if(i%dj[j]==0)break;
}
}
int qa;
for(int i=1;i<=q;i++){
qa=read();
cout<<dj[qa]<<endl;
}
return 0;
}
gcd求最大公约数:
int gcd(int a,int b){
if(b==0) return a;
else return gcd(b,a%b);
}
注意:两个数的乘积等于他们的最大公约数和最小公倍数的乘积。
快速幂:快速求a的b次方:
#include<iostream>
#include<cstdio>
using namespace std;
long long a,b,c;
long long ksm(long long a,long long b){
if(b==1) return a%c;
else {
long long tmp=ksm(a,b/2)%c;
return (((b%2==0? 1: a)%c*tmp)%c*tmp)%c;
}
}
int main(){
cin>>a>>b>>c;
printf("%ld^%ld mod% ld=%ld",a,b,c,ksm(a,b)%c);
return 0;
}
注意:求幂运算很容易炸int,所以一定longlong,并且要不断取余;
两数乘积的余数等于两个数取余的乘积。