首页 > 其他分享 >20240203-图论随记

20240203-图论随记

时间:2024-02-03 10:45:34浏览次数:19  
标签:图论 int 20240203 long 100005 edge dis id 随记

最短路

负环判断

#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

相关文章

  • 20240130-DP以及优化随记
    状态转移方程递归关系(从已知求得未知的表达式)背包dp0-1背包,多重,完全,混合模版套用//多重背包#include<bits/stdc++.h>usingnamespacestd;constintN=507,M=1e5+7;intp,n,x,y,z,dp[10005];intmain(){ cin>>p>>n; for(inti=1;i<=n;i++){ scanf("%d%d......
  • 20240201-高级数据结构随记
    intmain(){intn;cin>>n;for(inti=1;i<=n;i++){scanf("%d",&a[i]);sum[i]=sum[i-1]+a[i];}intmn=sum[0];for(inti=1;i<=n;i++){//枚举右端点if(sum[i]-mn>ans)ans=sum[i]-mn;......
  • 20240202-训练赛随记
    机场检录//二分#include<bits/stdc++.h>usingnamespacestd;longlongn,m,a[100005];boolcheck(longlongx){longlongt=0;for(inti=1;i<=n;i++)t+=(x/a[i]);returnt>=m;}intmain(){cin>>n>>m;for(inti=1;i<......
  • 代数最值与函数随记
    代数式\(ax^2+bx+c\)的最值是(),()时有最大值,()有最小值。代数解\[ax^2+bx+c\]\[=a(x^2+\frac{b}{a}x)+c\]\[=a[(x^2+\frac{b}{a}x+(\frac{b}{2a})^2]+c-\frac{b^2}{4a^2}·a\]\[=a(x+\frac{b}{2a})^2+\frac{4ac-b^2}{4a}\]\(\therefore\)易得,当\(x=-\fr......
  • 算法随记_1 蛇形矩阵(偏移量法)
    蛇形矩阵title:(在线学习平台)link:(https://www.acwing.com/)cover:(https://cdn.acwing.com/media/activity/surface/log.png)输入两个整数n和m,输出一个n行m列的矩阵,将数字1到n×m按照回字蛇形填充至矩阵中。具体矩阵形式可参考样例。输入样例33输出样例12......
  • 图论---可视区域获取(C++)
    1.开源库获取   地址:http://en.wikipedia.org/wiki/Visibility_graph2.使用使用处包含头文件 #include"visilibity.hpp"即可,以下面在Qt中使用为例:1/*2=========AVisiLibityExampleProgram=========3Thisprogramprovidesatextinterfacewhic......
  • 海亮01/23图论专题
    海亮01/23图论专题个人题单T12CF156D题意给定一个\(n\)个点\(m\)条边的带标号无向图,它有\(k\)个连通块,求添加\(k-1\)条边使得整个图连通的方案数,答案对\(p\)取模。题解没学过\(Prüfer\)序列的自行学习。不太会严谨证明我们发现,如果将\(k\)个连通块缩成一......
  • 图论总结——拓扑排序
    图论总结——拓扑排序例\(1\):排水系统(不是很模板的模板题)思路模板题,但是要进行分数约分,所以又不是很模板直接进行计算即可。注意计算过程中很可能爆\(long~~long\)类型范围,需要用\(int128\)类型进行存储。\(Code\)#include<bits/stdc++.h>#defineintlonglongusi......
  • 图论总结——拓扑排序
    图论总结——拓扑排序例\(1\):排水系统(不是很模板的模板题)思路模板题,但是要进行分数约分,所以又不是很模板直接进行计算即可。注意计算过程中很可能爆\(long~~long\)类型范围,需要用\(int128\)类型进行存储。代码#include<bits/stdc++.h>#defineintlonglongusingn......
  • 图论练习笔记
    P1606[USACO07FEB]LilypadPondG首先跳的过程肯定不会经过相同位置,所以之前经过的位置可以视为原状态,所以可以把添加的莲花数量视为当前路径长度,问题也就转化成了最短路计数。因为求的是添加莲花的方案数而不是经过路径的方案数,所以可以把已有的莲花连通块缩起来,以水格子为状......