图论相关基础

图论基础

存图

邻接矩阵
邻接表:
vector

初始化:vector<结构体名> G[10001][21];

读入:q[x][y].push_back((结构体名字){读入的数据})

struct edge {
    int to, w;//表示终点,权值。
};
int n, m, k;
vector<int> G[10001];
int main() {
    scanf("%d%d%d", &n, &m);//表示点数,边数。
    for (int i = 1; i <= m; i++) {
        int a, b, c;//代表一个边起点,终点,权值。
        scanf("%d%d%d", &a, &b, &c);
        G[a].push_back((edge) {b, c});//按照结构体类型强压,变量顺序要按照在结构体中定义的顺序。
    }
        G[a][i].to; //以a为起点的第i条边终点为to(前面村的对应的c)
        G[a][i].w;//同理。
        //对于像迪杰斯特拉等需要遍历以某点为起点的我们照样i<=G[a].size即可
    return 0;
}
链式前向星
struct ty
{
	int t,w,next;
}
int m;//边数 
ty edge[N];
int head[N];
void insertEdge(int x,int y,int z)
{  
   	edge[++m].t=x;
   	edge[m].w=z;
	edge[m].next=head[x]; 
	head[x]=m;
}

欧拉回路

无向图:连通且度为偶数

有向图:连通,每个点的入度和出度相同

混合图

拓扑排序

菜肴制作(优先队列的拓扑排序)
#include<iostream>
#include<queue>
#include<cstring>

using namespace std;

int cnt,n,m;//n为点数,m为边数
struct ty
{
    int y,next;
}edge[100010];
int head[100010];
void addedge(int x,int y)
{
    edge[++cnt].y=y;
    edge[cnt].next=head[x];
    head[x]=cnt;
}
int inc[100010];
int ans[100010];
priority_queue<int>q;
bool tuopo()
{
    while(!q.empty()) q.pop();
    for(int i=1;i<=n;i++)
        if(inc[i]==0) q.push(i);
    int num=0;
    while(!q.empty())
    {
        int x=ans[++num]=q.top();
        q.pop();
        for(int i=head[x];i!=-1;i=edge[i].next)
        {
            int y=edge[i].y;
            inc[y]--;
            if(inc[y]==0) q.push(y);
        }
    }
    if(num<n) return 0;
    else return 1;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        //int n,m;
        scanf("%d%d",&n,&m);
        cnt=0;
        memset(head,-1,sizeof(head));
        memset(inc,0,sizeof(inc));
        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            addedge(y,x);
            inc[x]++;
        }
        if(tuopo()==0) cout<<"Impossible!";
        else 
            for(int i=n;i>=1;i--)
                cout<<ans[i]<<' ';
                    cout<<endl ;
    }
    return 0;
}

拓扑排序可以判断有无环,能拓扑排序的一定没有环

AOE网

带边权的无环图

关键路径

最早时间和最晚时间相同的事件

最短路

单源最短路

松弛操作

dijkstra算法

不含负权边

链式前向星版

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int N=10010;

struct ty
{
	int t,w,next;
};

int head[10010];
ty edge[20010];
int cnt;

void addedge(int x,int y,int z)
{
	edge[++cnt].t=y;
	edge[cnt].next=head[x];
	edge[cnt].w=z;
	head[x]=cnt;
}

int dis[10010];
int st[10010];
struct ty2
{
	int x,dis;
	bool operator < (const ty2 &a)const
	{
		return dis>a.dis;
	}
	
};
priority_queue<ty2>q;

int dij(int s,int t)
{
	memset(dis,0x3f,sizeof(dis));
	dis[s]=0;
	ty2 tmp;
	tmp.x=s,tmp.dis=dis[s];
	q.push(tmp);
	while(!q.empty())
	{
		ty2 tmp=q.top();
		q.pop();
		if(st[tmp.x])continue;
		st[tmp.x]=1;
		for(int i=head[tmp.x];i!=-1;i=edge[i].next)
		{
			int y=edge[i].t;
			if(st[y])continue;
			if(dis[y]>dis[tmp.x]+edge[i].w)
			{
				dis[y]=dis[tmp.x]+edge[i].w;
				ty2 tmp2;
				tmp2.x=y;
				tmp2.dis=dis[y];
				q.push(tmp2);
			}
		}
		
	}
	return dis[t];
}

int main()
{
	int n,m,s,t;
	cin>>n>>m>>s>>t;
	memset(head,-1,sizeof(head));
	int a,b,v;
	for(int i=1;i<=m;++i)
	{
		cin>>a>>b>>v;
		addedge(a,b,v);
		addedge(b,a,v);
	}
	
	int ans=dij(s,t);
	if(ans>=0x3f3f3f)ans=-1;
	cout<<ans<<endl;
	return 0;
}

矩阵版

#include<iostream>
#include<cstring>
#include<algorithm> 
using namespace std;
int n,m,s,t;
int g[10010][10010];
int dist[10010];
bool st[10010];
int dijkstra(){
    memset(dist,0x3f3f3f,sizeof dist);//初始化为正无穷
    dist[s]=0;
    for(int j=1;j<=n;++j){
        int t=-1;
        if(!st[j]&&(t==-1||dist[t]>dist[j])){
            t=j;//找出当前未在s中标记且距离源点最近的点
        }//先找最小权重的t 
        st[t]=true;//标记t
        for(int j=1;j<=n;++j){
            dist[j]=min(dist[j],dist[t]+g[t][j]);
        }

    }
    return dist[t];

} 
int main(){

    cin>>n>>m>>s>>t;
    memset(g,0x3f3f,sizeof g);
    while(m--){
        int a,b,c;
        cin>>a>>b>>c;//稠密图使用邻接表来表示 
        g[a][b]=g[b][a]=min(g[a][b],c);//同两个边之间可能存在两条不同权重的边,取权重最小的 
    }
    int tt=dijkstra();
    if(tt>=0x3f3f)tt=-1;
    cout<<tt;
}
BellmanFord(spfa)

可以有负权边,但不能有负环

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;

struct ty
{
  int t,next,w;	
};
int n,m,s,t;
int inqueue[10010];
int dist[10010];
int head[10010];
ty edge[20010];
int cnt;
queue<int>q;

void addedge(int x,int y,int z)
{
	edge[++cnt].t=y;
	edge[cnt].w=z;
	edge[cnt].next=head[x];
	head[x]=cnt;
}

int spfa(int s,int t)
{
	memset(dist,0x3f3f,sizeof(dist));
	dist[s]=0;
	inqueue[s]=1;
	q.push(s);
	while(!q.empty())
	{
		int x=q.front();
		q.pop();
		inqueue[x]=0;
		for(int i=head[x];i!=-1;i=edge[i].next)
		{
			int y=edge[i].t;
			if(dist[y]>dist[x]+edge[i].w)
			{
				dist[y]=dist[x]+edge[i].w;
				if(!inqueue[y])
				{
					q.push(y);
					inqueue[y]=1;
				}
			}
		}
	}
	return dist[t];
	
}

int main()
{
	memset(head,-1,sizeof(head));
	cin>>n>>m>>s>>t;
	int a,b,v;
	for(int i=1;i<=m;++i)
	{
		cin>>a>>b>>v;
		addedge(a,b,v);
		addedge(b,a,v);
	}
	int ans=spfa(s,t);
	if(ans>=0x3f3f3f)ans=-1;
	cout<<ans;
	return 0;
}
多源最短路
Floyd
void floyd()
{
	for(int k=1;k<=n;++k)
	{
		for(int i=1;i<=n;++i)
		{
			for(int j=1;j<=n;++j)
			{
				if((i!=j)&&(j!=k)&&(i!=k))
				{
					if(dist[i][j]>dist[i][k]+dist[k][j])
					{
						dist[i][j]=dist[i][k]+dist[k][j];
					}
				}
			}
		}
	}
}

最小生成树

Prim
#include<iostream>
#include<cstring>
#include<queue> 
using namespace std;

int n,m;
int a,b,v;

struct ty
{
	int t,next,w;
};
int head[500000+10];
ty edge[2*500000+10];
int cnt=0;
int ans=0;

struct ty2
{
	int x,len;
	bool operator <(const ty2 &a)const
	{
		return len>a.len;
	}
};
priority_queue<ty2> q;
bool intree[500000+10];

void prim()
{
	ty2 tmp;
	intree[1]=1;
	for(int i=head[1];i!=-1;i=edge[i].next)
	{
		tmp.x=edge[i].t;
		tmp.len=edge[i].w;
		q.push(tmp);
	}
	
	while(!q.empty())
	{
		ty2 tmp=q.top();
		q.pop();
		int x=tmp.x;
		if(intree[x])continue;
		intree[x]=1;
		ans+=tmp.len;
		for(int i=head[x];i!=-1;i=edge[i].next)
		{
			int y=edge[i].t;
			if(intree[y])continue;
			tmp.x=y;
			tmp.len=edge[i].w;
			q.push(tmp);
		}
	}
}

void addedge(int x,int y,int z)
{
	edge[++cnt].t=y;
	edge[cnt].w=z;
	edge[cnt].next=head[x];
	head[x]=cnt;
}



int main()
{
	memset(head,-1,sizeof(head));
	cin>>n>>m;
	for(int i=1;i<=m;++i)
	{
		cin>>a>>b>>v;
		addedge(a,b,v);
		addedge(b,a,v);
	}
	prim();
	cout<<ans;
	return 0;
}
Kruskal

利用并查集

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

int n,m;
struct ty
{
	int x,y,w;
};
ty edge[500010];

bool cmp(ty a,ty b)
{
	return a.w<b.w;
}

int fa[500010];
int find(int x)
{
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;++i)
	{
		fa[i]=i;
	}
	for(int i=1;i<=m;++i)
	{
		cin>>edge[i].x>>edge[i].y>>edge[i].w;
	}
	sort(edge+1,edge+1+m,cmp);
	int ans=0;
	for(int i=1;i<=m;++i)
	{
		int fx=find(edge[i].x);
		int fy=find(edge[i].y);
		if(fx==fy)continue;
		fa[fx]=fy;
		ans+=edge[i].w;
	}
	cout<<ans<<endl;
	return 0;
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值