补题补题2.13

You are given a simple undirected graph with �N vertices and �M edges. The vertices are numbered 11 to

 我刚开始写这个,一直套模板,然后一直时间超限,本来以为数字范围太大,要初始化所有的数还是有点吃力。但是不是这样的(去看下面)

但是还是想贴出来一下(时间超限的代码): 

#include<stdio.h>
int f[200010];
int n,m,a,b;
int getf(int v)
{
    if(f[v]==v)return v;
    else return getf(f[v]);
}
int merges(int u,int v)
{
    int t1;
    int t2;
    t1=getf(u);
    t2=getf(v);
    if(t1!=t2)
    {
        f[t2]=t1;
        return 1;
    }
    return 0;

}
int main()
{

    scanf("%d %d",&n,&m);
    //init();

    int count=0;
    int k=m;
    for(int i=1; i<=m; i++)
    {
        scanf("%d %d",&a,&b);
        if(f[a]==0)
            f[a]=a;
        if(f[b]==0)f[b]=b;
        if(merges(a,b))k--;

    }

    printf("%d\n",k);
    return 0;
}

还是这位小姐姐:

(10条消息) 2023.2.12(总结)_小郭同学1564的博客-CSDN博客

我看到她的思路后就以为是我的想法不太行,然后按照她的思路试了n次:

但是还是一直超限,直到:

终于被我摸索出了自己的问题:

所以这里先稍微修改一下上面的代码,并稍微优化一下献上过了的代码吧!

#include<stdio.h>
int f[200010];
int n,m,a,b;
int getf(int v)
{
    if(f[v]==v)return v;
    return (f[v]=getf(f[v]));
}
int merges(int u,int v)
{
    int t1;
    int t2;
    t1=getf(u);
    t2=getf(v);
    if(t1!=t2)
    {
        f[t2]=t1;
        return 1;
    }
    return 0;

}
int main()
{

    scanf("%d %d",&n,&m);
    //init();

   
    int k=m;
    for(int i=1; i<=m; i++)
    {
        scanf("%d %d",&a,&b);
        if(f[a]==0)
            f[a]=a;
        if(f[b]==0)f[b]=b;
        if(merges(a,b))k--;

    }

    printf("%d\n",k);
    return 0;
}

 其实这里不这么写也可以,可以先将每一项都先初始化也可以过,而这里的话只初始化想要融合的,而不用每一个都初始化,将两个不是同一个父亲的数变成同一个,并且返回一,这时候就k--,表示这是一条符合题意的有效边被减掉,不断进行此类操作,减掉所有有效边不就只剩无效边了?也就是循环的边。

而现在,我来重点看看我犯的错误,其实我上上面的代码没有问题,就只是少了一个东西,让它的速度大大减慢,那就是

int getf(int v)
{
    if(f[v]==v)return v;
    return (f[v]=getf(f[v]));
}

其实我刚开始是这样写的

int getf(int v)
{
    if(f[v]==v)return v;
    else return getf(f[v]);
}

 其实这两个的代码的上面一个代码的操作看起来多了一步,其实这一步很关键,叫做路径压缩,就像是我们每一次要找的是祖先,但是我只知道你的爸爸,所以只能你的爸爸的爸爸的爸爸来找到祖先,但是在我们求到了祖先之后就可以直接把这个数的爸爸更新为祖先,就大大缩短了找的时间。之所以会缩短时间:我只要找祖先,所以找爸爸的步骤就可以全省了。简而言之,区别就在于:下面的那个就只是找到了祖先,上面那个还进行了更新操作。

Given an array �a consisting of �n elements, find the maximum possible sum the array can have after

 有点困了先献上代码吧!

 (11条消息) 2023.2.5(总结)_小郭同学1564的博客-CSDN博客

 这位小姐姐的的博客真的yyds,每次写不出了,她都在哈哈。

#include<stdio.h>
#include<math.h>
int a[200020];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf_s("%d",&n);
        int c=0;
        for(int i=1; i<=n; i++)
            scanf_s("%d",&a[i]);
        for(int i=1; i<=n; i++)
            if(a[i]<0){a[i]=-a[i];c++;}
        long long sum=0;
        for(int i=1; i<=n; i++)
        {
            sum+=a[i];
        }
        if(c%2==0)
        {
            printf("%lld\n",sum);
        }
        else
        {
            long long  min=9999999999;
            for(int i=1; i<=n; i++)
                if(a[i]<min)min=a[i];

            printf("%lld\n",sum-2*min);

        }



    }
    return 0;
}

不知道为什么那个虚拟裁判有时候可能卡了,我有时候用scanf不可以,但是scanf有时候又可以了。。

先来说一下这个个代码的思路,可以想到只要是相邻的数字就可以都变换符号,所以,如果这一串数字里面有偶数个符号,不断变换到一定次数后可以全部变成正数,这时候的和最大。当负号数为奇数时,这时候不管怎么变换,最多只能将符号变为一个,所以要使这一串数的和最大,就可以将那个符号调整到这一串数的绝对值的最小值上去。这样求得的和可以保证最大。刚开始我就没想过负号还可以想调到那就调到哪去,但是画完图后我不敢反驳:

最后一次后,1就可以变为-1;我们再来看偶数:

 

对于这个代码,虽然改来改去终于过了,但是还存在疑问,下面来解决一下:

我刚开始用的是abs取绝对值,它一直没过,在我不断的尝试下,才找到自己的问题:

#include<stdio.h>
#include<math.h>
int a[200020];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        int c=0;
        for(int i=1; i<=n; i++)
            scanf("%d",&a[i]);
        for(int i=1; i<=n; i++)
            if(a[i]<0)c++;
        long long sum=0;
        for(int i=1; i<=n; i++)
        {
            sum+=abs(a[i]);
        }
        if(c%2==0)
        {
            printf("%lld\n",sum);
        }
        else
        {
            int  min=10000000000;
            for(int i=1; i<=n; i++)
                if(abs(a[i])<min)min=a[i];

            printf("%lld\n",sum+2*min);

        }



    }
    return 0;
}

这是我之前的代码,因为我把符号为奇数的最小值一直看做的是负号,但是忘记了还可以是正号,这时候你可以;所以要将后面这一坨改为:

for(int i=1; i<=n; i++)
                if(abs(a[i])<min)min=abs(a[i]);

            printf("%lld\n",sum-2*min);

这样不管是正号还是负号就都可以写了;

最后来点小鸡汤收尾:

听到闹钟铃声比听到上课铃声还沉重,但是一想到这被窝是青春的坟墓,我就不敢继续睡下

去了。我可不愿意被埋在那里!哈哈!祝你情绪完美如早上的一缕清风

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值