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);
这样不管是正号还是负号就都可以写了;
最后来点小鸡汤收尾:
听到闹钟铃声比听到上课铃声还沉重,但是一想到这被窝是青春的坟墓,我就不敢继续睡下
去了。我可不愿意被埋在那里!哈哈!祝你情绪完美如早上的一缕清风