图论


#图论

图的储存

1.邻接矩阵

2.邻接表

struct tyc{int x,t,l,ne;} e[M];
int v[N];
void put (int x,int y,int l){
    num++;e[num]={x,y,l,v[x]};
    v[x]=num;
}

//枚举点x的所有出边
for(int i=v[x];i;i=e[i].ne) i是出边

最短路径

floyd

//复杂度O(n^3)
for(int k=1;k<=n;k++)
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);

dijkstra

需要注意的是:dijkstra无法用于处理带负权值的图

dijkstra的主要思路是分蓝白点,确定最短路长度的是白点,蓝点反之。
复杂度是相对比较优秀的O(n^2);

	int S=1;
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++){
	    if(dis[S][i]!=-1) d[i]=dis[S][i];
		else d[i]=inf;
	}
	int k=0;
	vis[S]=true;
	d[0]=inf;
	for(int i=1;i<n;i++){
	    int mn=inf,k=0;
	    for(int j=1;j<=n;j++)
	        if(!vis[j] && d[j]<=mn)  mn=d[j],k=j;//用变量mn筛出此时距离S最近的点
	    vis[k]=1;
	    for(int j=1;j<=n;j++){
	        if(!vis[j] && dis[k][j]!=-1)
	            d[j]=min(d[j],dis[k][j]);
	    }
	}

上述代码,如果加上常数,其复杂度应是O(2n^2)。
值的注意的是,通过堆进行优化的dijkstra复杂度更加优秀,可以达到O(n
(logn+n)),当数据很大的时候,会比上述复杂度优秀不少。

//堆优化后的dij
struct tyc {
	int id,v;//v 表示上文中的d[x]
	friend bool operator < (tyc a,tyc b) {
		return a.v>b.v;
	} 
};

priority_queue<tyc> que;

void Dijkstra(){
	int S=1;
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++){
	    if(dis[S][i]!=-1) d[i]=dis[S][i];
		else d[i]=inf;
	}
	que.push((tyc){1,0});
    rep(i,1,n){
        que.push((tyc){i,d[i]});
    }
	int x,y;
    d[0]=inf;
	while(!que.empty()){
		x = que.top().id, y = que.top().v;
		que.pop();
		if(vis[x]) continue;
		vis[x]=1;
		for(int j=1;j<=n;j++) {
			if(vis[j]) continue;
			if(dis[x][j]!=-1 && dis[x][j] < d[j]) {
				d[j] = dis[x][j];
				que.push((tyc){j,d[j]});
			}
		}
	}
}

最小生成树

Prim

基本思路与Dijkstra相同

int Prim(){	
	int ans=0;
	int S=1;
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++){
	    if(dis[S][i]!=-1) d[i]=dis[S][i];
		else d[i]=inf;
	}
	int k=0;
	vis[S]=true;
	d[0]=inf;
	for(int i=1;i<n;i++){
	    int mn=inf,k=0;
	    for(int j=1;j<=n;j++)
	        if(!vis[j] && d[j]<=mn)  mn=d[j],k=j;//用变量mn筛出此时距离S最近的点
	    vis[k]=1;
	    ans+=d[k];//!!!!!!!!!!!
	    for(int j=1;j<=n;j++){
	        if(!vis[j] && dis[k][j]!=-1)
	            d[j]=min(d[j],dis[k][j]);
	    }
	}
	return ans;
}

堆优化版:


struct tyc {
	int id,v;//v 表示上文中的d[x]
	friend bool operator < (tyc a,tyc b) {
		return a.v>b.v;
	} 
};

priority_queue<tyc> que;



int Prim(){	
	int ans=0;
	int S=1;
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++){
	    if(dis[S][i]!=-1) d[i]=dis[S][i];
		else d[i]=inf;
	}
	que.push((tyc){1,0});
    rep(i,1,n){
        if(d[i]==inf) continue;
        que.push((tyc){i,d[i]});
    }
	int x,y;
    d[0]=inf;
	while(!que.empty()){
		x = que.top().id, y = que.top().v;
		que.pop();
		if(vis[x]) continue;
		vis[x]=1;
        ans+=y;
		for(int j=1;j<=n;j++) {
			if(vis[j]) continue;
			if(dis[x][j]!=-1 && dis[x][j] < d[j]) {
				d[j] = dis[x][j];
				que.push((tyc){j,d[j]});
			}
		}
	}	
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值