最小生成树与最短路问题

最小生成树与最短路问题

  • 最小生成树(标准算法)

    #include<iostream>
    #include<string>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define Max 10101
    struct Node
    {
        int u,v,w;
        bool operator<(const Node&s)const
        {
            return w<s.w;
        }
    };
    int fa[Max];
    
    int Find(int i)
    {
        if(fa[i]==i) return i;
        else return fa[i]=Find(fa[i]);
    }
    
    int main()
    {
        int n,m;
        while(cin>>n&&n!=0)
        {
            cin>>m;
            struct Node s[Max];
            ll all=0;
            int i;
            for(i=1;i<=n;i++) fa[i]=i;
            int len=0;
            for(i=0;i<m;i++) cin>>s[i].u>>s[i].v>>s[i].w;
            sort(s,s+m);
            for(i=0;i<m;i++)
            {
                int u=s[i].u; int v=s[i].v; int w=s[i].w;
                if(Find(u)!=Find(v))
                {
                    fa[Find(u)]=fa[Find(v)];
                    len++;
                    all+=w;
                }
            }
            cout<<all<<endl;
        }
    }
    
  • 最小生成树(简便算法)

    		
    主要大纲:
    		for(i=1;i<=N;i++)  dis[i]=len[1][i]; //第一个到其他的联通值
            x[1]=true;
            for(i=1;i<N;i++)
            {
                int mini=1e9+7;
                int k=0;
                for(t=1;t<=N;t++)
                if(x[t]==false&&mini>dis[t])  //求最小值(可以为0) (则已联通,只需求。			联通的和自己。到其他的最小值)
                {
                    mini=dis[t];
                    k=t;
                }
                x[k]=true; all+=mini;
                for(t=1;t<=N;t++)
                if(x[t]==false&&len[k][t]<dis[t])  //更新为(联通的和自己)到其他单元的较小			联通值
                {
                    dis[t]=len[k][t];
                }
            }
    		cout<<all<<endl;
    
  • 最短路算法(简便算法)

    将最小生成树中  if(x[t]==false&&len[k][t]<dis[t]) {
                    dis[t]=len[k][t];
                }
     改为         if(x[t]==false&&dis[k]+len[k][t]<dis[t])
         		{
                    dis[t]=len[k][t]+dis[k];
                }
    
  • 最短路算法(节约内存版)(Bellman-Ford算法)

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    int u[200010],v[200010],l[200010];
    ll dis[20010];
    int main()
    {
        int n,m;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            int i,t;
            for(i=1;i<=m;i++) scanf("%d%d%d",&u[i],&v[i],&l[i]);
            for(i=2;i<=n;i++) dis[i]=1e9+7;
            int check=0;
            for(i=1;i<=n;i++)
            {
                int check=0;
                for(t=1;t<=m;t++)
                if(dis[v[t]]>dis[u[t]]+l[t])
                {
                    dis[v[t]]=dis[u[t]]+l[t];
                    check++;
                }
                if(check==0) break;
            }
            for(i=2;i<=n;i++) cout<<dis[i]<<endl;
        }
    }
    
  • 含负环最短路

    //含有负权边的单源点最短路径
    //动态规划思想:两点之间的最短路径最多经过n-1边即可到达
    //那么依次更新经过1条边,2条边,...,n-1条边的最短路径
    int main()
    {
        int dis[10],bak[10],i,k,n,m,u[10],v[10],w[10],check,flag;
        int inf=99999999;
        //读入n和m,n表示顶点个数,m表示边的条数
        scanf("%d %d",&n,&m);
    
        //读入边
        for(i=1;i<=m;i++) scanf("%d%d%d",&u[i],&v[i],&w[i]);
     
        //初始化dis数组,这里是1号顶点到其余各顶点的初始路程
        for(i=1;i<=n;i++)
            dis[i]=inf;
        dis[1]=0;
     
        //Bellman-Ford算法核心语句
        for(k=1;k<=n-1;k++)
        {
            //进行一轮松弛
            int check=0;
            for(i=1;i<=m;i++)
            if(dis[v[i]]>dis[u[i]]+w[i]){     //这里好像将图的边看成了有向边
                dis[v[i]]=dis[u[i]]+w[i];
                check++;
            }
            //松弛完毕后检测dis数组是否有更新
            if(check==0)
                break;    //数组没有更新,提前退出循环算法
        }
        //检测负权回路
        flag=0;
        for(i=1;i<=m;i++)
        if(dis[v[i]]>dis[u[i]]+w[i])
            flag=1;
        if(flag==1)
            printf("此图含负权回路\n");
        else
        {
            for(i=1;i<=n;i++)
                printf("%d ",dis[i]);
        }
        return 0;
    }
    
  • 树(+dfs)问题

    水图 (nowcoder.com)

    小w不会离散数学,所以她van的图论游戏是送分的
    小w有一张n个点n-1条边的无向联通图,每个点编号为1~n,每条边都有一个长度
    小w现在在点x上
    她想知道从点x出发经过每个点至少一次,最少需要走多少路
    输入描述:
    第一行两个整数 n,x,代表点数,和小w所处的位置
    第二到第n行,每行三个整数 u,v,w,表示u和v之间有一条长为w的道路
    输出描述:
    一个数表示答案
    
    /*
    解题思路:1.原图为一棵树
            2.经过每一点则经过每一条边一次或两次
            3.找到x出发的最长路ans, 2*sum-ans 即为所求解
    */
    
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    struct Node
    {
        int to;
        ll len;
        Node(int a,ll b) {
            to=a; len=b;
        }
    };
    vector<Node>g[50010];
    bool dis[50010];
    ll maxi=0;
    void dfs(int x,ll s)
    {
        dis[x]=true;
        int check=0;
        if(g[x].size()>0)
        {
            for(int i=0;i<g[x].size();i++)
            {
                int v=g[x][i].to;
                if(!dis[v])
                {
                    check++;
                    dis[v]=true;
                    dfs(v,s+g[x][i].len);
                    dis[v]=false;
                }
            }
        }
        if(check==0) maxi=max(s,maxi);
    }
    int main()
    {
        int n,x;
        while(scanf("%d%d",&n,&x)!=EOF)
        {
            int i,t;
            int u,v; ll w;
            ll sum=0;
            for(i=1;i<n;i++)
            {
                scanf("%d%d%lld",&u,&v,&w);
                g[u].push_back({v,w});
                g[v].push_back({u,w});
                sum+=w;
            }
            memset(dis,false,sizeof(dis));
            dfs(x,0);
            cout<<2*sum-maxi<<endl;
        }
    }
    
  • 最短路( + bfs)问题(二维方格图)

    PUBG (nowcoder.com)

    最近,喜爱ACM的PBY同学沉迷吃鸡,无法自拔,于是又来到了熟悉的ERANGEL。经过一番搜寻,PBY同学准备动身前往安全区,但是,地图中埋伏了许多LYB,PBY的枪法很差,希望你能够帮他找到一条路线,每次只能向上、下、左、右移动,尽可能遇到较少的敌人。
    输入描述:
    题目包含多组测试,请处理到文件结束;
    第一行是一个整数n,代表地图的大小;
    接下来的n行中,每行包含n个整数a,每个数字a代表当前位置敌人的数量;
    1 < n <= 100,1 <= a <= 100,-1代表当前位置,-2代表安全区。
    输出描述:
       对于每组测试数据,请输出从当前位置到安全区所遇到最少的敌人数量,每个输出占一行
    输入
    	5
    	6 6 0 -2 3
    	4 2 1 2 1
    	2 2 8 9 7
    	8 1 2 1 -1
    	9 7 2 1 2
    输出
    	9
    
/*
解题思路:1.记录每点代价
		2.bfs搜索,排序,代价小的放前面
		3.到达终点即退出
*/
#include<bits/stdc++.h>
using namespace std;
int ox,oy,sx,sy;
struct Node
{
    int u,v;
    int w;
    Node(int uu,int vv,int ww)
    {
        u=uu; v=vv; w=ww;
    }
    bool operator<(const Node& a) const{
        return a.w<w;
    }
};
int s[110][110];
bool f[110][110];
int mx[4]={0,0,-1,1},my[4]={1,-1,0,0};
void bfs(int xo,int yo)
{
    priority_queue<Node>m;     //优先队列操作
    m.push({xo,yo,0});
    f[xo][yo]=false;
    s[xo][yo]=0;
    while(!m.empty())
    {
        Node mm=m.top();
        m.pop();
        for(int i=0;i<4;i++)
        {
            int lx=mm.u+mx[i],ly=mm.v+my[i],ls=mm.w+s[lx][ly];
            if(lx==sx&&ly==sy) { printf("%d\n",ls); return; }
            if(f[lx][ly])
            {
                m.push({lx,ly,ls});
                f[lx][ly]=false;
            }
        }
    }
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        int i,t,x;
        memset(f,false,sizeof(f));
        for(i=1;i<=n;i++)
        for(t=1;t<=n;t++)
        {
            scanf("%d",&x);
            if(x>=0) s[i][t]=x;
            else if(x==-1) { ox=i; oy=t;  }
            else { sx=i; sy=t; s[i][t]=0; }
            f[i][t]=true;
        }
        bfs(ox,oy);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏的雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值