FZU_2195_检查站点(单源最短路)

传送门:http://acm.fzu.edu.cn/problem.php?pid=2195


题型:图论


题意:中文题,不解释


分析:

       试想先序遍历一棵树,必然只有根到某个叶子节点的路径不会回溯,且其他的边都会被回溯且只回溯一次,所以寻找最小的回溯权值和,只需要找到那一条权值最大的路径,然后用所有边权和减去就可以了。

       最简单的办法就是单源最短路求出根到所有叶子节点的路径权值,然后选最大就可以了。


代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<queue>

#define mt(a,b) memset(a,b,sizeof(a))
using namespace std;
const int inf=0x3f3f3f3f;
const int M=1000010;

bool vis[M];

class Spfa { ///单源最短路o(2*ME)
    typedef int typec;///边权的类型
    static const int ME=1000010;///边的个数
    static const int MV=1000010;///点的个数
    struct E {
        int v,next;
        typec w;
    } e[ME];
    int n,le,head[MV],inque[MV];
    typec dist[MV];
    bool used[MV];
    queue<int> q;
public:
    void init(int tn) { ///传入点的个数
        n=tn;
        le=0;
        mt(head,-1);
    }
    void add(int u,int v,typec w) {
        e[le].v=v;
        e[le].w=w;
        e[le].next=head[u];
        head[u]=le++;
    }
    bool solve(int s) { ///传入起点,下标0开始,存在负环返回false
        for(int i=0; i<n; i++) {
            dist[i]=inf;
            used[i]=true;
            inque[i]=0;
        }
        used[s]=false;
        dist[s]=0;
        inque[s]++;
        while(!q.empty()) q.pop();
        q.push(s);
        while(!q.empty()) {
            int u=q.front();
            q.pop();
            used[u]=true;
            for(int i=head[u]; ~i; i=e[i].next) {
                int v=e[i].v;
                if(dist[v]>dist[u]+e[i].w) {
                    dist[v]=dist[u]+e[i].w;
                    if(used[v]) {
                        used[v]=false;
                        q.push(v);
                        inque[v]++;
                        if(inque[v]>n) return false;
                    }
                }
            }
        }
        return true;
    }
    typec getdist(int id) {
        return dist[id];
    }
} gx;

int main() {
    int n;
    while(~scanf("%d",&n)) {
        int m = n-1;
        int total = 0;
        int u,v,w;
        gx.init(n);
        mt(vis,true);
        vis[0] = false;
        while(m--) {
            scanf("%d%d%d",&u,&v,&w);
            gx.add(u-1,v-1,w);
            total += w;
            vis[u-1] = false;
        }

        gx.solve(0);

        int maxn = -1;
        for(int i=1; i<n; i++) {
            if(vis[i]) {
                maxn = max(maxn,gx.getdist(i));
            }
        }

        printf("%d\n",total-maxn);

    }

    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值