图论梳理

最短路

spfa存负边

Dijkstra最短路径
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+7;
const int inf=0x3f3f3f3f;
int n,m;
int tot=0;
int head[maxn];
int dis[maxn];
bool vis[maxn];
int pre[maxn];
struct AC{
	int to;
	int next;
	int w;
	int d;
}edge[maxn];
void init(){
	memset(head,-1,sizeof(head));
	memset(vis,false,sizeof(vis));
	//memset(pre,-1,sizeof(pre));
	fill(dis,dis+maxn,inf);
}
void addedge(int u,int v,int d,int w){
	edge[tot].to=v;
	edge[tot].w=w;
	edge[tot].d=d;
	edge[tot].next=head[u];
	head[u]=tot++;
}
void dijkstra(int x){
	fill(dis,dis+maxn,inf);
	dis[x]=0;
	for(int i=0;i<n;i++){
		int u=-1,min=inf;
		for(int j=0;j<n;j++){
			if(dis[j]<min&&vis[j]==false){
				u=j;
				min=dis[j];
			}
		}
		if(min==inf){
			break;
		}
		vis[u]=true;
		for(int j=head[u];j!=-1;j=edge[j].next){
			int v=edge[j].to;
			if(vis[v]==false&&dis[v]>dis[u]+edge[j].w){
				dis[v]=dis[u]+edge[j].w;
				pre[v]=u;
			}
		}
	}
}
int main(){
	init();
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		int u,v,d,w;
		int flag;
		scanf("%d%d%d%d%d",&u,&v,&flag,&d,&w);
		addedge(u,v,d,w);
		if(flag==0)
		addedge(v,u,d,w);
	}
	int s,e;
	scanf("%d%d",&s,&e);
	dijkstra(s);
	vector<int>ve;
	vector<int>::iterator it;
	pre[s]=-1;
	//cout<<dis[e]<<endl;
	while(pre[e]!=-1){
		ve.push_back(e);
		e=pre[e];
	}
	reverse(ve.begin(),ve.end());
	cout<<s<<" ";
	for(it=ve.begin();it!=ve.end();it++){
		cout<<*it<<" ";
	}
	return 0;
}
SPFA
#include<iostream>
#include<cstring>
#include<queue> 
using namespace std;
const int maxn=1e5+7;
int head[maxn];
int vis[maxn],dis[maxn];
queue<int>que;
int tot;
struct AC{
	int to;
	int w;
	int next;
}edge[maxn];
void init(){
	memset(head,-1,sizeof(head));
	tot=1;
}
void addedge(int u,int v,int w){
	edge[tot].to=v;
	edge[tot].w=w;
	edge[tot].next=head[u];//存之前相同起始点的边 
	head[u]=tot++;
}
void SPFA(int s){
	int u,l=0,r;
	que.push(s);
	vis[s]=1;
	dis[s]=0;
	while(!que.empty()){
		u=que.front();
		que.pop();
		vis[u]=0;
		for(int i=head[u];i!=-1;i=edge[i].next){
			if(dis[edge[i].to]>dis[u]+edge[i].w){
				dis[edge[i].to]=dis[u]+edge[i].w;
				if(!vis[edge[i].to]){
					vis[edge[i].to]=1;
					que.push(edge[i].to);
				}
			}
		}
	}
}
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	init();
	for(int i=0;i<m;i++){
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		addedge(a,b,c);
		//adddege(b,a,c);
	}
	SPFA(1);
	
} 

最小生成树

prim
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+7;
const int inf=0x3f3f3f3f;
int n,m;
int tot=0;
int head[maxn];
int dis[maxn];
bool vis[maxn];
int pre[maxn];
struct AC{
	int to;
	int next;
	int w;
	int d;
}edge[maxn];
void init(){
	memset(head,-1,sizeof(head));
	memset(vis,false,sizeof(vis));
	//memset(pre,-1,sizeof(pre));
	fill(dis,dis+maxn,inf);
}
void addedge(int u,int v,int d,int w){
	edge[tot].to=v;
	edge[tot].w=w;
	edge[tot].d=d;
	edge[tot].next=head[u];
	head[u]=tot++;
}
void dijkstra(int x){
	fill(dis,dis+maxn,inf);
	dis[x]=0;
	for(int i=0;i<n;i++){
		int u=-1,min=inf;
		for(int j=0;j<n;j++){
			if(dis[j]<min&&vis[j]==false){
				u=j;
				min=dis[j];
			}
		}
		if(min==inf){
			break;
		}
		vis[u]=true;
		ans+=dis[u]; 
		for(int j=head[u];j!=-1;j=edge[j].next){
			int v=edge[j].to;
			if(vis[v]==false&&dis[v]>edge[j].w){
				dis[v]=edge[j].w;
			}
		}
	}
}
int main(){
	
}
克鲁斯卡尔-kruskal
在这里插入代码片

二部图最大匹配

匈牙利算法-最大匹配

矩阵表示 时间复杂度O(n^3)

#include<bits/stdc++.h> 
using namespace std;
int g[maxn][maxn];
int used[maxn];
int girl[maxn];
int n,m;
bool find(int x){
	for(int i=1;i<=m;i++){
		if(g[x][i]&&used[i]==0){
			used[i]=1;
			if(girl[i]==0||find(girl[i])){
				girl[i]=x;
				return true;
			}
		}
	}
	return false;
}
int main(){
	for(int i=1;i<=n;i++){
		ans+=find(i);
	}
}

最小边覆盖

边覆盖集

边覆盖集:通俗的讲,所谓边覆盖集,就是G中所有的顶点都是E*中某条边的邻接顶点(边覆盖顶点),一条边只能覆盖2各顶点

注意:在无向图中存在用尽量少的边去“覆盖”住所有的顶点(注意:单独一个点没有与他相连的边,也算作一次边去覆盖这个点),所以边覆盖集有极小与最小的区别。
极小边覆盖:若边覆盖E中的任何真子集都不是边覆盖集,则称E是极小边覆盖集。
最小边覆盖:边数最小的边覆盖集称为最小边覆盖。
最小边覆盖=最大独立集=n-最大匹配

最小路径覆盖

用尽量少的不相符交叉简单路径覆盖无环图G的所有节点(不交叉指的是原图,而非后来构造的二分图)。即覆盖点(同样的,在路径覆盖中单独一个点没有与他相连的边,也算一次路径去覆盖这个点)。建立一个二分图模型,把所有顶点i拆成两个:X集中的i和Y集中的i’,如果有边i->j,则在二分图中引入边i->j’,结果就是最小路径覆盖 = N - 最大匹配数。(N为原图中结点数)
最小路径覆盖和最小边覆盖不同
不要求给的图是二分图,要求有向无环图吧
详细描述 POJ-1422 POJ-2594

最小点覆盖

最小点覆盖=最大匹配

km-最佳匹配

解决带权二分图的匹配问题,在保证最大匹配的前提使得权值和最大。

  1. 分别为左右点设置标杆,左边初始为最大值,右边设置为0.
  2. 对于左边的点,首先考虑权值最大的边与之相连,连接的前提是左右点的标杆值和等于权值。
  3. 存在矛盾就减少增光路上左边的权值同时增加增光路右边的权值。
  4. 重复以上步骤知道匹配结束。
#include<bit/stdc++.h>
using namespace std;
const int maxn=1e3+7;
const int inf=0x3f3f3f3f;
int n;
int usex[maxn],usey[maxn],topx[maxn],topy[maxn],slack[maxn];
int girl[maxn],g[maxn][maxn];
bool dfs(int x){
	usex[x]=1;
	for(int i=1;i<=n;i++){
		if(usey[i])continue;
		int temp=topx[x]+topy[i]-g[x][i];
		if(temp!=0){
			slack[i]=min(temp,slack[i]);//¼Ç¼×îС½µµÍÖµ 
		}
		else{
			usey[i]=1;
			if(girl[i]==-1||dfs(girl[i])){
				girl[i]=x;
				return true;
			}
		}
	}
	return false;
}
int km(){
	memset(girl,-1sizeof(girl));
	memset(topx,0,sizeof(topx));
	memset(topy,0,sizeof(topy));
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			topx[i]=max(topx[i],g[i][j]);
		}
	}
	for(int i=1;i<=n;i++){
		memset(slack,inf,sizeof(slack));
		while(1){
			memset(usex,0,sizeof(usex));
			memset(usey,0,sizeof(usey));
			if(dfs(i))break;
			int temp=inf;
			for(int j=1;j<=n;j++){
				if(usey[j])continue;
				temp=min(tem,slack[j]);
			}
			if(temp==inf)return -1;
			for(int j=1;j<=n;j++){
				if(usex[j])
				topx[j]-=temp;
			}
			for(int j=1;j<=n;j++){
				if(usey[j])
				topy[j]+=temp;
				else
				slack[j]-=temp;
			}
		}
	}
	int d=inf;
	for(int i=1;i<=n;i++){
		if(!usex[i])continue;
		for(int j=1;j<=mj++){
			if(usey[j])continue;
			d=min(d,topx[i]+topy[j]-g[i][j]);
		}
	}
	for(int i=1;i<=n;i++){
		if(usex[i])topx[i]-=d;
	}
	for(int i=1;i<=m;i++){
		if(usey[i])topy[i]+=d;
	}
}
int main(){
	
}

感觉学长的板子有点问题
km两个例题

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值