zoukankan      html  css  js  c++  java
  • P5687 [CSP-SJX2019]网格图 题解

    题目链接

    1.题外话

    停课了。刷刷之前的题可以RP++;

    2.解题意

    n*m,很规则的期盼图。

    a[]表示水平相邻两个点之间点的边权,b[]则是竖着两个点之间的边权值。

    每一个都只给你n/m个数据,表明这一行/列的边权值全都相同。

    题目就是让你求这么一个图的最小生成树的边权值之和。

    3.找思路

    习惯性的浏览一下数据范围。如果暴力的话克鲁斯卡尔肯定是跑不过的,只能拿部分分。想要拿满分,肯定要用到题目给我们的特殊性质。

    考虑一下克鲁斯卡尔的原理:边权从小到大排序,如果遇到能成环的就跳过,否则就把边加入到最小生成树中。

    对于这道题,因为它一行,一列上的边权全部相同,那么他们被加入到最小生成树的概率是等价的。

    如果你假设每一行的边都加入了最小生成树,那么此时一定存在一个扩充生成树的方案:

    把列中权值最小的竖着的边加入进去,如下图(红色边表示已经被加入到最小生成树中):

     选取权值最小的一列加入:

    这样一来,才是最小生成树。

     同样,对于列都选满的情况,权值最小的行也一定会被加入到生成树中来。

    那么首先,sort一遍a,b,把权值最小的(下标为1)的边加入到最小生成树中来。因为这些边是一定会加入进来的;

    这里的加边是可以降低复杂度的,因为一行/一列会被同时加入进来。


    考虑之后的做法:

    一个显然的想法是从行列综合考虑,按照权值从小到大加如一行/一列边。因为如果不选这个权值较小的,sort后下标更大的边将不会比它更优;

    然后呢我们遇到一个很明显的阻碍:判环。

    解决方法也很简单:我们不在一整列一整行地加入进入,而是除去那些 连接之前已经被加入的行/列的边后加入。

    语言描述不当,画图理解来补:

    假如我们已经选好了行和列中最优的:

     接下来我们发现a[2]>b[2],也就是这时候列比行更优,我们尝试尽可能多的加入这一行:

    (注意:b[2]不一定是第二列哦)

     因为第三行是“之前已经被加入的行”,那么我们必须要舍去其中一条连接它与当前这一列。也就是说,图中绿色的列要舍去一个。由于我们要的答案是权值和而不是具体的选择方案,那么这两条边选哪个也就无所谓了。计算权值时我们只需把边数减一即可。

    就这样进行下去,直到n行/m列其中一个被选满为止。宣告结束,最小生成树生成。

    4.代码

    #include<cstdio>
    #include<algorithm>
    #define N 300007
    #define ll long long
    using namespace std;
    int n,m,a[N],b[N];
    ll ans=0;
    inline int read()
    {
        int ans=0;
        char ch=getchar(),last=' ';
        while(ch>'9'||ch<'0')last=ch,ch=getchar();
        while(ch>='0'&&ch<='9')ans=(ans<<3)+(ans<<1)+ch-'0',ch=getchar();
        return last=='-'?-ans:ans;
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            a[i]=read();
        }
        for(int i=1;i<=m;i++)
        {
            b[i]=read();
        }
        sort(a+1,a+1+n);
        sort(b+1,b+1+m);
        ans+=(ll)a[1]*(m-1)+(ll)b[1]*(n-1);
        int l=1,h=1,cnt1=2,cnt2=2;
        while(cnt1<=n&&cnt2<=m)
        {
            if(a[cnt1]<=b[cnt2])ans+=(ll)a[cnt1++]*(m-l),h++;
            else ans+=(ll)b[cnt2++]*(n-h),l++;
        }
        printf("%lld",ans);
    }

    希望对各位有所帮助。

    祝NOIP2020rp++

  • 相关阅读:
    Oracle建立表空间和用户
    Session详解
    Spring中AOP方式实现多数据源切换
    Filter(过滤器)学习
    不用加号运算
    数字转化为十六进制
    1px像素问题(移动端经典问题)
    对postcss-plugin-px2rem的研究
    npm cache clean --force
    对async/await的研究
  • 原文地址:https://www.cnblogs.com/lbssxz/p/13626990.html
Copyright © 2011-2022 走看看