(模板4)图论

本文详细讲解了网格DFS、八皇后问题的递归解决方案、BFS和DFS寻找最短路径(包括Dijkstra和SPFA)、负权最短路算法(Bollman Ford)、Floyd算法、Prim和Kruskal求最小生成树,以及染色法判断二分图和匈牙利算法。这些算法是信息技术中解决经典问题的重要工具。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

网格dfs
#include<bits/stdc++.h>
using namespace std;

int vis[25][25];
char maze[25][25];
int dx[]={-1,0,1,0};
int dy[]={0,1,0,-1};
int n,m;
int fx,fy,ans=1;

bool check(int x,int y){
    return x<0||x>=n||y<0||y>=m;
}

void dfs(int x,int y){
    vis[x][y]=1;
    for(int i=0;i<=3;i++){
        int a=x+dx[i];
        int b=y+dy[i];
        if(!check(a,b)&&vis[a][b]==0&&maze[a][b]=='.'){
            ans++;
            dfs(a,b);
        }
    }
}
int main(){
    while(cin>>m>>n,n||m){
        memset(vis,0,sizeof vis);
        for(int i=0;i<n;i++){、。 、
            for(int j=0;j<m;j++){
                cin>>maze[i][j];
                if(maze[i][j]=='@'){
                    fx=i;fy=j;
                }
            }
        }
        dfs(fx,fy);
        cout<<ans<<endl;
        ans=1;
    }
    return 0;
}

n皇后
#include<bits/stdc++.h>
using namespace std;
const int N=20;
char g[N][N];
bool col[N],dj[N],udj[N];
int n;
void dfs(int r){
    if(r==n){
        for(int i=0;i<n;i++) puts(g[i]);
        puts("");
        return;
    }
    for(int i=0;i<n;i++){
        if(!col[i]&&!dj[r+i]&&!udj[n-r+i]){
            g[r][i]='Q';
            col[i]=dj[r+i]=udj[n-r+i]=true;
            
            dfs(r+1);
            
            col[i]=dj[r+i]=udj[n-r+i]=false;
            g[r][i]='.';
        }
    }
}
int main(){
    cin>>n;
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            g[i][j]='.';
    dfs(0);
    return 0;
}

网格bfs
#include<bits/stdc++.h>
using namespace std;
const int N=25;
int vis[N][N];
char maze[N][N];
typedef pair<int,int> PII;
#define x first
#define y second
int n,m,fx,fy;
int dx[]={-1,0,1,0};
int dy[]={0,1,0,-1};

bool check(int x,int y){
	return x<0||x>=n||y<0||y>=m;
} 
int bfs(int fx,int fy){
	vis[fx][fy]=1;
	queue<PII> q;
	q.push({fx,fy});
	int ans=0;
	while(q.size()){
		PII t=q.front();
		q.pop(); 
		ans++;
		for(int i=0;i<4;i++){
			int a=t.x+dx[i];
			int b=t.y+dy[i];
			if(check(a,b)||vis[a][b]==1||maze[a][b]=='#') continue;
			vis[a][b]=1;
			q.push({a,b});
		}	
	} 
	return ans;
}
int main(){
	while(cin>>m>>n,n||m){
		memset(vis,0,sizeof vis);
		for(int i=0;i<n;i++){
			for(int j=0;j<m;j++){
				cin>>maze[i][j];
				if(maze[i][j]=='@'){
					fx=i;
					fy=j;
				}
			}
		}
	cout<<bfs(fx,fy)<<endl;
	}
	return 0;
}
bfs求最短距离
#include<bits/stdc++.h>
using namespace std;
int x,y,d,m,n;
const int N=25;
char maze[N][N];
int vis[N][N];
int dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}};
struct node{
    int x,y,d;
    node(int xx,int yy,int dd){
        x=xx;
        y=yy;
        d=dd;
    }
};
bool in(int x,int y){
    return x<m&&x>=0&&y>=0&&y<n;
}
int bfs(int sx,int sy){
    queue<node> q;
    q.push(node(sx,sy,0));
    vis[sx][sy]=1;
    while(!q.empty()){
        node now=q.front();
        q.pop();
        for(int i=0;i<4;i++){
            int tx=now.x+dir[i][0];
            int ty=now.y+dir[i][1];
            if(in(tx,ty)&&maze[tx][ty]!='#'&&vis[tx][ty]==0){
                if(maze[tx][ty]=='*')
                {
                    return now.d+1;
                }
			else
				{
                    vis[tx][ty]=1;
                    q.push(node(tx,ty,now.d+1));
                }
            }
        }
    }
    return -1;
}
int main(){
    scanf("%d%d",&m,&n);
    for(int i=0;i<m;i++){
        scanf("%s",&maze[i]);
        for(int j=0;j<n;j++){
            if(maze[i][j]=='@'){
                x=i;y=j;
            }
        }
    }
 cout<<bfs(x,y)<<endl;
    
    return 0;
}

Dijkstra()(朴素版)
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=510;
int g[N][N];    //为稠密阵所以用邻接矩阵存储
int dist[N];    //用于记录每一个点距离第一个点的距离
bool st[N];     //用于记录该点的最短距离是否已经确定
int n,m;
int Dj ()
{
    memset(dist, 0x3f,sizeof dist);     //初始化距离  0x3f代表无限大
    dist[1]=0;  //第一个点到自身的距离为0
    for(int i=0;i<n;i++)      //有n个点所以要进行n次 迭代
    {
        int t=-1;       //t存储当前访问的点
        for(int j=1;j<=n;j++)   //这里的j代表的是从1号点开始
            if(!st[j]&&(t==-1||dist[t]>dist[j]))     
                t=j;
        st[t]=true;   
        for(int j=1;j<=n;j++)           //依次更新每个点所到相邻的点路径值
            dist[j]=min(dist[j],dist[t]+g[t][j]);
    }
    if(dist[n]==0x3f3f3f3f) return -1;  //如果第n个点路径为无穷大即不存在最低路径
    return dist[n];
}
int main()
{
    cin>>n>>m;
    memset(g,0x3f,sizeof g);    //初始化图 因为是求最短路径
                                //所以每个点初始为无限大
    while(m--)
    {
        int x,y,z;
        cin>>x>>y>>z;
        g[x][y]=min(g[x][y],z);     //如果发生重边的情况则保留最短的一条边
    }
    cout<<Dj ()<<endl;
    return 0;
}

Dijkstra()(堆优化版)
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=1e6+10;
int dist[N];
bool st[N];//标记数组
int e[N],h[N],w[N],ne[N],idx;
int n,m;
void add(int a,int b,int c){
	e[idx]=b;
	w[idx]=c;
	ne[idx]=h[a];
	h[a]=idx++;
}
int dj(){
	memset(dist,0x3f,sizeof dist);
	dist[1]=0;
	priority_queue<PII,vector<PII>,greater<PII > > heap;
	heap.push({0,1});
	while(heap.size()){
		PII t=heap.top();
		heap.pop();
		int ver=t.second,distance=t.first;

		if(st[ver]) continue;
		st[ver]=true;

		for(int i=h[ver];i!=-1;i=ne[i]){
			int j=e[i];
			if(dist[j]>distance+w[i]){
				dist[j]=distance+w[i];
				heap.push({dist[j],j});
			}
		}
	}
	if(dist[n]==0x3f3f3f3f) return -1;
	return dist[n];
}

int main(){
	memset(h,-1,sizeof h);
	cin>>n>>m;
	while(m--){
		int a,b,c;
		cin>>a>>b>>c;
		add(a,b,c);	
	}
	cout<<dj()<<endl;
	return 0;
}
Bollman_Ford
#include<bits/stdc++.h>
using namespace std;
const int N=510,M=10010;
int n,m,k;
int dist[N],backup[N];
struct Edge
{
	int a,b,w;
}edges[M];
int bf(){
    memset(dist,0x3f3f3f3f,sizeof dist);
    dist[1]=0;
	for(int i=0;i<k;i++){
		memcpy(backup,dist,sizeof dist);
		for(int j=0;j<m;j++)
		{
			int a=edges[j].a,b=edges[j].b,w=edges[j].w;
			dist[b]=min(dist[b],backup[a]+w);
		}
	}
	if(dist[n]>0x3f3f3f3f/2) return -1;
	return dist[n]; 
}
int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=0;i<m;i++){
		int a,b,w;
		cin>>a>>b>>w;
		edges[i]={a,b,w};
	}
	int t=bf();
	if(bf()==-1) puts("impossible");
	else cout<<t<<endl;
	
	return 0;
}

spfa求负权最短路
#include<bits/stdc++.h>
using namespace std;
const int N=100100;
int n,m;      // 总点数
int h[N], w[N], e[N], ne[N], idx;  // 邻接表存储所有边
int dist[N];        // 存储每个点到1号点的最短距离
bool st[N];     // 存储每个点是否在队列中
void add(int a,int b,int c)
{
    e[idx]=b;
    w[idx]=c;
    ne[idx]=h[a];
    h[a]=idx++;
}
// 求1号点到n号点的最短路距离,如果从1号点无法走到n号点则返回-1
int spfa()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;

    queue<int> q;
    q.push(1);
    st[1] = true;

    while (q.size())
    {
        int t = q.front();
        q.pop();
        st[t] = false;
        for (int i = h[t]; i != -1; i = ne[i])
        {
            int j = e[i];
            if (dist[j] > dist[t] + w[i])
            {
                dist[j] = dist[t] + w[i];
                if (!st[j])     // 如果队列中已存在j,则不需要将j重复插入
                {
                    q.push(j);
                    st[j] = true;
                }
            }
        }
    }

    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}
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==-1) cout<<"impossible"<<endl;
    else cout<<t<<endl;
    return 0;
}
spfa求负环
#include<bits/stdc++.h>
using namespace std;
const int N=100100;
int n,m;      // 总点数
int h[N], w[N], e[N], ne[N], idx;  // 邻接表存储所有边
int dist[N],cnt[N];        // 存储每个点到1号点的最短距离
bool st[N];     // 存储每个点是否在队列中
void add(int a,int b,int c)
{
    e[idx]=b;
    w[idx]=c;
    ne[idx]=h[a];
    h[a]=idx++;
}
bool spfa()
{

    queue<int> q;
	for(int i=1;i<=n;i++)
	{
		st[i]=true;
		q.push(i);
	}
    while (q.size())
    {
        int t = q.front();
        q.pop();

        st[t] = false;

        for (int i = h[t]; i != -1; i = ne[i])
        {
            int j = e[i];
            if (dist[j] > dist[t] + w[i])
            {
                dist[j] = dist[t] + w[i];
                cnt[j]=cnt[t]+1;
                
                if(cnt[j]>=n) return true;
                if (!st[j])     // 如果队列中已存在j,则不需要将j重复插入
                {
                    q.push(j);
                    st[j] = true;
                }
            }
        }
    }
	return false;
}
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(spfa()) puts("Yes");
    else puts("No");
    return 0;
}

Floyd算法
#include<bits/stdc++.h>
using namespace std;
const int N=210,INF=1e9;
int n,m,q;
int d[N][N];
void floyd()
{
	for(int k=1;k<=n;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
			d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
int main()
{
	cin>>n>>m>>q;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(i==j) d[i][j]=0;
			else d[i][j]=INF;	
		}
	}
	
	while(m--)
	{
		int a,b,w;
		cin>>a>>b>>w;
		d[a][b]=min(d[a][b],w);	
	} 
	floyd();
	while(q--)
	{
		int a,b;cin>>a>>b;
		if(d[a][b]>INF/2)puts("impossible");
		else cout<<d[a][b]<<endl;
	}
	return 0;	
}

prim算法求最小生成树
#include<bits/stdc++.h>
using namespace std;
const int N=510,INF=0x3f3f3f3f;
int n,m;
int g[N][N];
int dist[N];
bool st[N];
int prim()
{
	memset(dist,0x3f,sizeof dist);
	int res=0;
	for(int i=0;i<n;i++)
	{
		int t=-1;
		for(int j=1;j<=n;j++)
		{
			if(!st[j]&&(t==-1||dist[t]>dist[j]))
				t=j;
		}
		if(i&&dist[t]==INF) return INF;
		if(i) res+=dist[t];
		for(int j=1;j<=n;j++)
			dist[j]=min(dist[j],g[t][j]);
			st[t]=true;
	}
	return res;
}
int main()
{
	cin>>n>>m;
	memset(g,0x3f,sizeof g);
	while(m--)
	{
		int a,b,c;
		cin>>a>>b>>c;
		g[a][b]=g[b][a]=min(g[a][b],c);
	}
	int t=prim();
	if(t==INF) puts("impossible");
	else cout<<t<<endl;
	return 0;
}

kruskal算法求最小生成树
#include<bits/stdc++.h>
using namespace std;
const int N=200010;
int n,m;
int p[N];
int INF=0x3f3f3f3f;
struct Edge
{
	int a,b,w;
	bool operator <(const Edge &W) const
	{
		return w<W.w;
	}
}edges[N];
int find(int x)
{
	if(p[x]!=x) p[x]=find(p[x]);
	return p[x];
}
int kruskal()
{
	sort(edges,edges+m);
	for(int i=1;i<=n;i++) p[i]=i;//初始化并查集
	int res=0,cnt=0;
	for(int i=0;i<m;i++)
	{
		int a=edges[i].a,b=edges[i].b,w=edges[i].w;
		a=find(a),b=find(b);
		if(a!=b)
		{
			p[a]=b;
			res+=w;
			cnt++;	
		}	
	}
	if(cnt< n-1) return INF;
	return res;
}
int main()
{
	cin>>n>>m;
	for(int i=0;i<m;i++)
	{
		int a,b,w;
		cin>>a>>b>>w;
		edges[i]={a,b,w}; 
	}
	int t=kruskal();
	if(t==INF) puts("impossible");
	else cout<<t<<endl;
	return 0;
}

染色法判别二分图
#include<bits/stdc++.h>
using namespace std;
const int N=100010,M=200010;
int n,m;
int h[N],e[M],ne[M],idx;
int color[N];
void add(int a,int b)
{
	e[idx]=b;
	ne[idx]=h[a];
	h[a]=idx++;
}
bool dfs(int u,int c)
{
	color[u]=c;
	for(int i=h[u];i!=-1;i=ne[i])
	{
		int j=e[i];
		if(!color[j])
		{
			if(!dfs(j,3-c)) return false;
		}
		else if(color[j]==c) return false;
	}
	return true;
}
int main()
{	
	cin>>n>>m;
	memset(h,-1,sizeof h);
	while(m--)
	{
		int a,b;
		cin>>a>>b;
		add(a,b);
		add(b,a);
	}
	bool flag=true;
	for(int i=1;i<=n;i++)
	{
		if(!color[i])
		{
			if(!dfs(i,1))
			{
				flag=false;
				break;
			}	
		}
	}
	if(flag) puts("Yes");
	else puts("No");
		
	return 0;
}

匈牙利算法
#include<bits/stdc++.h>
using namespace std;
const int N=510,M=200010;
int n1,n2,m;
int h[N],e[M],ne[M],idx;
int match[N];
bool st[N];
void add(int a,int b)
{
	e[idx]=b;
	ne[idx]=h[a];
	h[a]=idx++;
}
bool find(int x)
{
	for(int i=h[x];i!=-1;i=ne[i])
	{
		int j=e[i];
		if(!st[j])
		{
			st[j]=true;
			if(match[j]==0||find(match[j]))
			{
				match[j]=x;
				return true;
			}
		}
	}
	return false;
}
int main()
{	
	cin>>n1>>n2>>m;
	memset(h,-1,sizeof h);
	while(m--)
	{
		int a,b;
		cin>>a>>b;
		add(a,b);
	}
	int res=0;
	for(int i=1;i<=n1;i++)
	{
		memset(st,false,sizeof st);
		if(find(i)) res++;
	}
	cout<<res<<endl;
		
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值