zoukankan      html  css  js  c++  java
  • 洛谷 P1967 货车运输

    洛谷 P1967 货车运输

    题目链接:洛谷 P1967 货车运输

    算法标签: 图论生成树深度优先搜索(DFS)

    题目

    题目描述

    A国有n座城市,编号从 1到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

    输入格式

    第一行有两个用一个空格隔开的整数n,m,表示 A 国有n 座城市和 m 条道路。

    接下来 m行每行3个整数 x, y, z,每两个整数之间用一个空格隔开,表示从 x号城市到y号城市有一条限重为 z 的道路。注意: ** x 不等于 y,两座城市之间可能有多条道路 ** 。

    接下来一行有一个整数 q,表示有 q 辆货车需要运货。

    接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意: ** x 不等于 y ** 。

    输出格式

    共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1。

    输入输出样例

    输入 #1

    4 3
    1 2 4
    2 3 3
    3 1 1
    3
    1 3
    1 4
    1 3
    

    输出 #1

    3
    -1
    3
    

    题解:

    生成树(最大)+ DFS + 倍增LCA

    整体思路就是在最大生成树上找一条最小边,实现的过程就是在最大生成树上跑倍增LCA。

    那么既然这么说,我们就要单独把最大生成树建好(除去多余边),所以我们就需要在Kruskal的时候直接建树,具体代码实现:

    void kruskal()
    {
    	sort(edge + 1, edge + 1 + m, cmp);
    	for (int i = 1; i <= n; i ++ )
    	{
    		fa[i] = i;
    	}
    	for (int i = 1; i <= m; i ++ )
    	{
    		int fx = find(edge[i].x);
    		int fy = find(edge[i].y);
    		if (fx != fy)
    		{
    			fa[fx] = fy;
    			add(edge[i].x, edge[i].y, edge[i].val);
    			add(edge[i].y, edge[i].x, edge[i].val);
    		}
    	}
    }
    

    在建好最大生成树之后,我们要DFS做几个处理:

    1.处理出每个点的深度(LCA)

    2.处理好每个点的上1个点(LCA)

    3.处理好每个点到它的上一个点的距离(LCA边权)

    代码实现如下:

    void dfs(int x)
    {
    	for (int i = head[x]; i; i = nex[i])
    	{
    		int y = to[i];
    		if (deep[y])
    			continue ;
    		deep[y] = deep[x] + 1;
    		f[y][0] = x;
    		w[y][0] = val[i];
    		dfs(y);
    	}
    }
    

    最终求答案就是一个倍增LCA的板子,要注意在每一步向上倍增的时候都要记录答案(最小边边权)

    ans = min(ans, min(w[x][i], w[y][i]));

    最终的ans就是对于这一对询问的答案。

    LCA部分代码如下:

    int lca(int x, int y)
    {
    	if (find(x) != find(y))
    		return -1;
    	int ans = inf;
    	if (deep[x] > deep[y])
    		swap(x, y);
    	for (int i = 20; i >= 0; i -- )
    	{
    		if (deep[f[y][i]] >= deep[x])
    		{
    			ans = min(ans, w[y][i]);
    			y = f[y][i];
    		}
    	}
    	if (x == y) return ans;
    	for (int i = 20; i >= 0; i -- )
    	{
    		if (f[x][i] != f[y][i])
    		{
    			ans = min(ans, min(w[x][i], w[y][i]));
    			y = f[y][i];
    			x = f[x][i];
    		}
    	}
    	ans = min(ans, min(w[x][0], w[y][0]));
    	return ans;
    }
    

    AC代码

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int inf = 0x3f3f3f3f;
    
    const int MAXN = 10010;
    const int MAXM = 50050;
    
    int n, m, q;
    
    int fa[MAXN], deep[MAXN], f[MAXN][21], w[MAXN][21];
    
    int tot, to[MAXM], val[MAXM], nex[MAXM], head[MAXN];
    
    struct Edge{
    	int x, y, val;
    } edge[MAXM];
    
    bool cmp(Edge a, Edge b)
    {
    	return a.val > b.val;
    }
    
    int find(int x)
    {
    	if (fa[x] == x)
    		return x;
    	return fa[x] = find(fa[x]);
    }
    
    void add(int x, int y, int z)
    {
    	to[ ++ tot] = y;
    	val[tot] = z;
    	nex[tot] = head[x];
    	head[x] = tot;
    }
    
    void kruskal()
    {
    	sort(edge + 1, edge + 1 + m, cmp);
    	for (int i = 1; i <= n; i ++ )
    	{
    		fa[i] = i;
    	}
    	for (int i = 1; i <= m; i ++ )
    	{
    		int fx = find(edge[i].x);
    		int fy = find(edge[i].y);
    		if (fx != fy)
    		{
    			fa[fx] = fy;
    			add(edge[i].x, edge[i].y, edge[i].val);
    			add(edge[i].y, edge[i].x, edge[i].val);
    		}
    	}
    }
    
    void dfs(int x)
    {
    	for (int i = head[x]; i; i = nex[i])
    	{
    		int y = to[i];
    		if (deep[y])
    			continue ;
    		deep[y] = deep[x] + 1;
    		f[y][0] = x;
    		w[y][0] = val[i];
    		dfs(y);
    	}
    }
    
    int lca(int x, int y)
    {
    	if (find(x) != find(y))
    		return -1;
    	int ans = inf;
    	if (deep[x] > deep[y])
    		swap(x, y);
    	for (int i = 20; i >= 0; i -- )
    	{
    		if (deep[f[y][i]] >= deep[x])
    		{
    			ans = min(ans, w[y][i]);
    			y = f[y][i];
    		}
    	}
    	if (x == y) return ans;
    	for (int i = 20; i >= 0; i -- )
    	{
    		if (f[x][i] != f[y][i])
    		{
    			ans = min(ans, min(w[x][i], w[y][i]));
    			y = f[y][i];
    			x = f[x][i];
    		}
    	}
    	ans = min(ans, min(w[x][0], w[y][0]));
    	return ans;
    }
    
    int main()
    {
    	scanf("%d%d", &n, &m);
    	for (int i = 1; i <= m; i ++ )
    	{
    		scanf("%d%d%d", &edge[i].x, &edge[i].y, &edge[i].val);
    	}
    	kruskal();
    	scanf("%d", &q);
    	for (int i = 1; i <= n; i ++ )
    	{
    		if (!deep[i])
    		{
    			deep[i] = 1;
    			dfs(i);
    			f[i][0] = i;
    			w[i][0] = inf;
    		}
    	}
    	for (int i = 1; i <= 20; i ++ )
    	{
    		for (int j = 1; j <= n; j ++ )
    		{
    			f[j][i] = f[f[j][i - 1]][i - 1];
    			w[j][i] = min(w[j][i - 1],w[f[j][i - 1]][i - 1]);
    		}
    	}
    	for (int i = 1; i <= q; i ++ )
    	{
    		int x, y;
    		scanf("%d%d", &x, &y);
    		printf("%d
    ", lca(x, y));
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    oracle11g windows客户端安装
    leetcode做题总结
    后端工程师都应该知道的最佳实践
    阿里云ubuntu下nginx部署上线后报错问题
    漫谈逆向工程
    RPC远程过程调用(Remote Procedure Call)
    stub和proxy使用初衷
    vue如何绑定多个class style
    简单又好看的背景 , 代码实现方格背景
    使用C#.NET调用ICU进行编码检测和编码转换
  • 原文地址:https://www.cnblogs.com/littleseven777/p/11842075.html
Copyright © 2011-2022 走看看