zoukankan      html  css  js  c++  java
  • P5687 网格图

    算法原理

    根据 (operatorname{Kruskal}) 算法的运算规则,每次总是会把当前边权最小,且连接着本不连通的两个点的边选中。

    而在这道题目中,位于同一行或列的边的边权大小一定是相同的,因此一定会接连选完这一行或列上所有可行的边。

    思考过程

    选择一行/列后,整个被选中的行/列上所有的点都位于同一个连通分量。

    故选完至少一行和至少一列后,接下来构成生成树的过程中,一定保证只存在一个包含两个及以上节点的连通分量。

    这是一个关键点,思考过程可以以这个点分成两部分。

    1. 在选完至少一行和一列之前,保证接下来选择的任何行/列,这一行/列上所有的边都会被选择。

    2. 而在选完至少一行和一列之后,对于即将被选择的一行来说,这一行上尚未被连接进最小生成树的点的个数 (=) 总的列数 (-) 已被选择的列数。而一条边在构建最小生成树时,只能将一个点与最小生成树连接起来。因此选择这一行能选择的边的条数,即等于这一行上尚未接入最小生成树的点的个数。即总列数 (-) 已被选择的列数。对于列来说同理。

    因此总的算法思路就明确了:

    1. 首先将所有的边权值放到一起升序排列,注意记录一下这个边权是横边的边权还是纵边的边权,开一个 pair 存很方便(自动按照第一关键字为索引进行升序排序)。一遍 sort 进行排序。开两个变量 (l ext{(line)})(c ext{(column)}) 存储已经选择的行/列数。

    2. 然后从小到大枚举排序后的边权,在两个统计变量都不为 (0) 之前,任何选的行/列都将其所包含的所有边全部加入最小生成树。

    3. 在两个统计变量都大于 (0) 之后,对于行来说,加入其包括的 (m-c) 条边,即可保证这一行上所有的点全部加入最小生成树,且不会影响到之后的选择,故可以保证正确性。列同理。

    Tips

    • 排序时把所有的边放在了一起,因此记得把数组开成两倍。
    • 不开 long long 见祖宗

    代码:

    #include<bits/stdc++.h>
    
    #define LL long long
    
    using namespace std;
    
    const int Maxe = 3e5 + 5;
    pair<LL, bool> a[Maxe << 1];
    int n, m;
    LL ans = 0;
    int main()
    {
    	scanf("%d%d", &n, &m);
    	for(register int i = 1; i <= n; ++i)
    	{
    		int x;
    		scanf("%d", &x);
    		a[i] = make_pair(x, false);
    	}
    	for(register int i = n + 1; i <= n + m; ++i)
    	{
    		int x;
    		scanf("%d", &x);
    		a[i] = make_pair(x, true);
    	}
    	sort(a + 1, a + n + m + 1);
    	int l = 0, c = 0;
    	for(register int i = 1; i <= n + m; ++i)
    	{
    		if(!a[i].second)
    		{
    			if((!l)||(!c))
    			{
    				ans += (long long)(m - 1) * a[i].first;
    			}
    			else
    			{
    				ans += (long long)(m - c) * a[i].first;
    			}
    			l++;
    		}
    		else
    		{
    			if((!l)||(!c))
    			{
    				ans += (long long)(n - 1) * a[i].first;
    			}
    			else
    			{
    				ans += (long long)(n - l) * a[i].first;
    			}
    			c++;
    		}
    	}
    	printf("%lld", ans);
    	return 0;
    }
    
  • 相关阅读:
    【编程题目】输入一个已经按升序排序过的数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。
    【编程题目】在一个字符串中找到第一个只出现一次的字符。如输入 abaccdeff,则输出 b。
    Unity3d 开发(七)AssetBundle组织文件夹
    MapReduce 的类型与格式【编写最简单的mapreduce】(1)
    Asterisk[1]
    1181: 念数字
    怎样創建 iOS 展開式 UITableView?
    android自己定义圆盘时钟
    iOS设计模式之NSNotificationCenter 消息中心
    大浪淘沙,JSP终将死去
  • 原文地址:https://www.cnblogs.com/zimujun/p/13679891.html
Copyright © 2011-2022 走看看