图复习

存储结构

//图的二维数组邻接矩阵存储
int n,e,w;    //定点数和边数 权值 
int g[101][101];
void  make1(){
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j=+) g[i][j]=0x7fffffff;
	} //初始化
	cin>>e; 
	int x,y;
	for(int i=1;i<=e;i++) {
		cin>>x>>y>>w;
		g[x][y]=w;
		g[y][x]=w; //这是由于无向图,所以有两句 
	}
} 

//邻接表
struct node{
	int from,to,dis;
	node(int a,int b,int c){
		from=a;to=b;dis=c;
	}
}; 
vector<node> adj[maxn];

//数组模拟邻接表
//专业名------链式前向星 
struct Edge{
	int next;  //下一条编的编号 
	int to;    //这条边的去处 
	int dis;   //边的权值 
}edge[1001];                   //这是边 
int head[101],num_edge;        //这是节点 

void add_edge(int from,int to,int dis){  //添加一条从from到to的距离为dis的单向边! 
	 edge[num_edge].to=to;
	 edge[num_edge].dis=dis;
	 edge[++num_edge].next=head[from];
	 head[from]=num_edge; 
}

void make2(){
	cin>>n>>e;
	num_edge=0;
	int x,y,d;
	for(int i=1;i<=e;i++){
		cin>>x>>y>>d;
		add_edge(x,y,d);
	}
	for(int i=head[1];i!=0;i=edge[i].next){
		//遍历操作 
	}
} 
int main(){
	
return 0;
}

  图的遍历

BFS、DFS

重要概念:

深度优先生成树

回退边

void dfss(int x,int depht){ //带层数的(邻接表版) 
	vis[x]=1;
	for(int i=1;i<=adj[x].size();i++){
		int j=adj[x][i];
		if(vis[j]) dfs(j,depth+1); //不需要判断是不是连接 
	}
}
//广度优先 
struct node{
	int v; //顶点编号
	int layer; //层号 
};
vector<node> ajd[MAXN];
void bfsss(int x,int layer){
	node start;
	start.v=x;  //起始编号
	start.layer=0;
	queue<node> q;
	q.push(start);
	vis[x]=1;
	while(!q.empty()){
		node now=q.front();
		q.pop();
		int u=now.v;
		for(int i=1;i<ajd[u].size();i++){
			node j=adj[u][i]; //相连的顶点
			j.layer=now.layer+1;
			if(vis[j.v]==0){
				q.push(j);
				vis[j.v]=1;
			} 
			
		}
	} 
}

//对整张图进行遍历
//如果图是联通的,那么只需要进行一次遍历了
void travdfs(){
	for(int i=1;i<=n;i++){
		if(vis[i]==0) dfs(i);
	}
} 
void travbfs(){
	for(int i=1;i<=n;i++){
		if(vis[i]==0) bfs(i,1);  //层数 
	} 

例:欧拉路(一笔画问题)、欧拉回路

从图中某个点出发遍历整个图,每条边通过且通过一次。

一、是否存在欧拉路或欧拉回路

(1)图应该是联通图:DFS或并查集

(2)无向图:全部都是偶点:存在欧拉回路

       有两个奇点:存在欧拉路,一个为起点,一个为终点

(3)有向图:每个点的出度标记为1,入度标记为-1,出度+入度即为度数,

        有向图存在欧拉回路:只有1个度为1(起点),1个度为-1(终点),其他都为0

二、输出欧拉回路:

递归DFS,在后面打印或记录,但是如果数据很大,就得采用非递归形式。

三、混合图欧拉回路问题:最大流

http://ybt.ssoier.cn:8088/problem_show.php?pid=1341

int n,e;
int circuit[101],d[101][101],c[101];  //c是每个点的度,用来判断是欧拉路还是欧拉回路 
int num;
void find(int i){
	for(int j=1;j<=n;j++){
		if(d[i][j]==1){
			d[i][j]=d[j][i]=0;  //删除这条边
			find(j); 
		}
	}
	circuit[++num]=i;  //记录路径 
}
//这是欧拉路(2个奇点),欧拉回路(0个奇点) 
int main(){
	cin>>n>>e;
	int x,y;
	memset(c,0,sizeof(c));
	memset(d,0,sizeof(d));
	for(int i=1;i<=e;i++){
		cin>>x>>y;
		d[x][y]=d[y][x]=1;
		c[x]++;
		c[y]++;
	} 
	int start=1;
	for(int i=1;i<=n;i++){
		if(c[i]%2==1) start=i; //从奇点开始 
	}
	num=0;
	find(start);
	for(int i=1;i<=num;i++) cout<<circuit[i]<<" ";
	cout<<endl; 
return 0;
}

  哈密尔顿环:不重复的走过所有的点,并且是回路

//哈密尔顿环:不重复的走过所有的点,并且是回路
//能找出所有的环 
int vi[1001],visted[1001],num[1001],g[1001][1001]; 
int length;
int ans[1001]; //保存答案 
int n,m,x;
void print(){
	for(int i=1;i<length;i++) cout<<ans[i]<<" ";
	cout<<ans[length]<<endl;
}
void dfs(int last,int i){  //上次访问的last,这次的i 
	visted[i]=1;
	vi[i]=1;     //标记 
	for(int j=1;j<=num[i];j++){
		if(g[i][j]==x&&g[i][j]!=last){
			ans[++length]=j;
			print();   //找到一个环,输出 
			length--;
			break; 
		}
		if(!visted[g[i][j]]) dfs(i,g[i][j]);  //遍历所有与i关联的点 
	}
	length--;
	visted[i]=0;  //回溯  不标记vi[],因为vi表示是否在图中出现过 
} 


int main(){
	memset(visted,0,sizeof(visted));
	memset(vi,0,sizeof(vi));
	cin>>n>>m;
	int y;
	for(int i=1;i<=m;i++){
		cin>>x>>y;
		g[x][++num[x]]=y;
		g[y][++num[y]]=x;
	}
	for(x=1;x<=n;x++){
		
		if(!vi[x]) {
		length=0;
		dfs(0,x);
		
		}  //以每一个点为起点遍历,因为不是任一个点都可以遍历出环的 
	}
	
return 0;
}

  

最短路径

dijkstra

猜你喜欢

转载自www.cnblogs.com/shirlybaby/p/12370182.html