最短路
负环判断
#include <bits/stdc++.h>
using namespace std;
struct node{
int from,to,v;
}edge[100005];
#define oo 2000000000
int dis[100005];
int main(){
int n,m,s,t;
cin>>n>>m>>s>>t;
for(int i=1;i<=m;i++){
scanf("%d %d %d",&edge[i].from,&edge[i].to,&edge[i].v);
}
for(int i=1;i<=n;i++) dis[i]=oo;
dis[s]=0;
bool ok=true;
for(int i=1;i<=n;i++){
bool f=1;
for(int j=1;j<=m;j++){
int a=edge[j].from;
int b=edge[j].to;
int c=edge[j].v;
if(dis[a]==oo) continue;
if(dis[b]>dis[a]+c){
dis[b]=dis[a]+c;
f=0;
}
}
if(f) break;
if(i==n) ok=false;
}
if(ok) cout<<"YES";
else cout<<"NO";
}
SPFA和Bellman-ford的相似之处和区别?
void SPFA(int s){
for(int i=1;i<=n;i++) dis[i]=oo;
dis[s]=0;
int l=0,r=0;
q[r++]=s;
while(l<r){
int k=q[l++];
for(int i=0;i<edge[k].size();i++){
int to=edge[k][i].to;
int v=edge[k][i].v;
if(dis[to]>dis[k]+v) {
dis[to]=dis[k]+v;
if(!mark[to]){
mark[to]=1;
q[r++]=to;
if(++cnt[to]==n)
}
}
}
}
}
#include<bits/stdc++.h>
using namespace std;
int n,m,d[150005],cnt[150005],h[150005],e[150005],w[150005],nxt[150005],id;
bool mark[150005];
void add(int a,int b,int c){
e[id]=b,nxt[id]=h[a],w[id]=c,h[a]=id++;
}
int spfa(){
queue<int> q;
for(int i=1;i<=n;i++){
q.push(i);
mark[i]=1;
}
while(q.size()){
int t=q.front();
q.pop();
mark[t]=1;
for(int i=h[t];i!=-1;i=nxt[i]){
int j=e[i];
if(d[j]>d[t]+w[i]){
d[j]=d[t]+w[i];
cnt[j]=cnt[t]+1;
if(cnt[j]>=n) return 1;
if(!mark[j]){
mark[j]=0;
q.push(j);
}
}
}
}
return 0;
}
int main(){
cin>>n>>m;
memset(h,-1,sizeof(h));
while(m--){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
}
int t=spfa();
if(t)puts("YES");
else puts("NO");
return 0;
}
Dijkstra
堆优化
struct node{
int to,v;
bool operator <(const node &a) const{
return v>a.v;
}
}
priority_queue<node> q;
bool mark[]
int main(){
for(int i=1;i<=n;i++){
dis[i]=oo;
mark[i]=0;
}
dis[s]=0;q.push((node){s,0});
while(!q.empty()){
node tmp=q.top();q.pop();
int k=tmp.to;
if(mark[k]) continue;
mark[k]=1;
for(int j=0;j<edge[k].size();j++){
int to=edge[k][j].to;
int v=edge[k][j].v;
if(dis[to]>dis[k]+v){
dis[to]=dis[k]+v;
q.push((node){to,dis[to]});
}
}
}
}
关键点
S ----> X ----> T
c1 c2
c1*c2=S---->T
关键边
总统要回家,即从走到,会经过一些街道,每条街道都是单向的并且拥有权值。现在,为了让总统更好的回家,要对每一条街道进行操作:
①如果该街道一定在最短路上,则输出“YES”。
②如果该街道修理过后,该边所在的最短路可以取代原先的最短路,则输出“CAN x”,x是修改该街道的最小花费,就是权值减小的值。
③如果该街道不在到的路径上,或者修改过后权值小于等于0,则输出“NO”。
#include <bits/stdc++.h>
#define ll long long
#define oo 2000000000
using namespace std;
long long a[100005],b[100005],l[100005],d1[100005],d2[100005],dfn[100005],low[100005],n,m,s,t,id;
bool bridge[100005],vis[100005];
vector<pair<long long,long long>> edge[100005];
void dijkstra(long long v,long long *d){
long long t;
priority_queue<pair<long long,long long>,vector<pair<long long,long long>>,greater<pair<long long,long long>>> q;
for(long long i=1;i<=n;i++) d[i]=oo;
d[v]=0;q.push(make_pair(0,v));
while(!q.empty()){
t=q.top().second;q.pop();
for(long long i=0;i<edge[t].size();i++){
if(d[edge[t][i].first]>d[t]+edge[t][i].second){
d[edge[t][i].first]=d[t]+edge[t][i].second;
q.push(make_pair(d[edge[t][i].first],edge[t][i].first));
}
}
}
return;
}
void tarjan(long long x){
id++;
dfn[x]=id;
low[x]=id;
for(long long i=0;i<edge[x].size();i++){
if(vis[edge[x][i].second]) continue;
vis[edge[x][i].second]=true;
if(!dfn[edge[x][i].first]){
tarjan(edge[x][i].first);
low[x]=min(low[x],low[edge[x][i].first]);
if(dfn[x]<low[edge[x][i].first]) bridge[edge[x][i].second]=true;
}
else low[x]=min(low[x],dfn[edge[x][i].first]);
}
return;
}
int main(){
cin>>n>>m>>s>>t;
for(long long i=0;i<m;i++) cin>>a[i]>>b[i]>>l[i];
for(long long i=0;i<m;i++) edge[a[i]].push_back(make_pair(b[i],l[i]));
dijkstra(s,d1);
for(long long i=1;i<=n;i++) edge[i].clear();
for(long long i=0;i<m;i++) edge[b[i]].push_back(make_pair(a[i],l[i]));
dijkstra(t,d2);
for(long long i=1;i<=n;i++) edge[i].clear();
for(long long i=0;i<m;i++){
if(d1[a[i]]+l[i]+d2[b[i]]==d1[t]){
edge[a[i]].push_back(make_pair(b[i],i));
edge[b[i]].push_back(make_pair(a[i],i));
}
}
tarjan(s);
for(long long i=0;i<m;i++){
if(bridge[i]) cout<<"YES"<<endl;
else if(d1[t]-d1[a[i]]-d2[b[i]]-1>0) cout<<"CAN "<<l[i]-(d1[t]-d1[a[i]]-d2[b[i]]-1)<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
最小生成树
Prim
算法
Prim算法基于贪心,我们每次总是选出一个离生成树距离最小的点去加入生成树,最后实现最小生成树
#include<bits/stdc++.h>
using namespace std;
#define inf 123456789
#define maxn 5005
#define maxm 200005
struct edge{
int v,w,next;
}e[maxm<<1];
int head[maxn],dis[maxn],cnt,n,m,tot,now=1,ans;
bool vis[maxn];
void add(int u,int v,int w){
e[++cnt].v=v;
e[cnt].w=w;
e[cnt].next=head[u];
head[u]=cnt;
}
void init(){
cin>>n>>m;
for(re int i=1,u,v,w;i<=m;++i){
cin>>u>>v>>w;
add(u,v,w),add(v,u,w);
}
}
int prim(){
for(re int i=2;i<=n;++i) dis[i]=inf;
for(re int i=head[1];i;i=e[i].next) dis[e[i].v]=min(dis[e[i].v],e[i].w);
while(++tot<n){
int minn=inf;
vis[now]=1;
for(re int i=1;i<=n;++i){
if(!vis[i]&&minn>dis[i]){
minn=dis[i];
now=i;
}
}
ans+=minn;
for(re int i=head[now];i;i=e[i].next){
re int v=e[i].v;
if(dis[v]>e[i].w&&!vis[v]) dis[v]=e[i].w;
}
}
return ans;
}
int main(){
init();
printf("%d",prim());
return 0;
}
Kruskal
算法
#include<bits/stdc++.h>
using namespace std;
struct Edge{
int u,v,w;
}edge[200005];
int fa[5005],n,m,ans,eu,ev,cnt;
bool cmp(Edge a,Edge b){
return a.w<b.w;
}
int find(int x){
while(x!=fa[x]) x=fa[x]=fa[fa[x]];
return x;
}
il void kruskal(){
sort(edge,edge+m,cmp);
for(int i=0;i<m;i++){
eu=find(edge[i].u), ev=find(edge[i].v);
if(eu==ev) continue;
ans+=edge[i].w;
fa[ev]=eu;
if(++cnt==n-1) break;
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=0;i<m;i++) edge[i].u=read(),edge[i].v=read(),edge[i].w=read();
kruskal();
printf("%d",ans);
return 0;
}
灌水
/______ a
/ /
/______ b
/ /
o/______ c
\ \
\ ______ d
\ \
\_______ e
最优比率生成树
∑ vi
----- >= mid
∑ ci
∑ (vi-mid*ci) >= 0
标签:图论,int,20240203,long,100005,edge,dis,id,随记
From: https://www.cnblogs.com/Firepaw-cattery/p/18004401