OJ 刷题随笔

输入与输出

  1. scanf函数的:
int a,b;
scanf("%d %d",&a,&b);
float c;
double d;
scanf("%f %lf",&c,&d);

类似的代码不管两个%d中间是空字符串,还是许多个空格,在输入的时候均可直接用一个空格或者换行符进行分隔

  1. scanf函数读取单个字符存入字符数组:
scanf("%c",&a[k]);

不管是空格还是换行符,均会读取,所以此时字符数组存储的东西是不完全的,可以在后面加上getchar()消除空格或换行

  • 特别注意
    当遇到类似的输入的时候
6
A
B
C
D
B
C

第一个表示接下来要输入的字符行数,我们想要把下面的几个存入字符数组,应该在读取数字的scanf后面再加一个getchar!!!

    int length;
    scanf("%d",&length);
    getchar();//这个不可以少!!!
    for(int i=0;i<length;i++){
        scanf("%c",&cows[i]);
        getchar();//这个当然得加
    }
  1. gets()函数
    gets()函数用来从标准输入设备(键盘)读取字符串直到换行符结束,但换行符会被丢弃,然后在末尾添加’\0’字符。其调用格式为:
char s[100];
gets(s);

其中s为字符串变量(字符串数组名或字符串指针)。
gets(s)函数与scanf("%s",s)相似,但不完全相同,使用scanf("%s",s) 函数输入字符串时存在一个问题,就是如果输入了空格会认为字符串结束,空格后的字符将作为下一个输入项处理,但gets()函数将接收输入的整个字符串直到遇到换行为止。

  1. putchar()函数
    用于输出单个字符

  2. string 与 char *

  • 当我们定义了一个string,就不能用scanf("%s",s)和printf("%s",s)输入输出。主要是因为%s要求后面是对象的首地址!!! 也就是char *
  • string 转 char*
include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
    string s="xiaoming";
    const char *a=s.c_str();//去掉const会显示编译错误
    const char *b=s.data();
    printf("a:[%s],b:[%s]\n",a,b);
}
  • char* 转 string
#include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
    char *a="xiaoming";
    string s;
    s=a;
    printf("%s\n",s.c_str());
}
  1. 输出函数printf
long long b=121;
double a=121.31;
printf("%lld %lf",b,a);

关于PE或WA

  1. 注意换行符号
  2. 注意最终的结果输出如果很大的话是否有换行要求,总之仔细审题!
  3. 有可能是让每个元素占3个位而不是每个元素之间俩空格!使用%3d进行输出
  4. 可能是因为读入字符的时候读入了空格,可以考虑换成cin>>进行字符的读取
  5. 可能需要用到高精度,或者long long
  6. 看看是不是对于0之类的结果设置的没有相应的输出
  7. sort函数在自定义比较函数的时候如果两个等价,最好是返回false
  8. 对于两个int类型a和b,他们的商如果赋值给double,必须进行强制类型转换
    ,否则将把一个int类型的结果赋值给double,这个商小数位是0的!

枚举

1. 可以重复的全排列

使用两个循环即可

2. 不可以重复的全排列

2.1 如果是n个元素,排列n个位置

使用如下的函数next_permutation(),如果有n个元素,那么有n!种情况

    char  a[4]={'a','b','c','d'};
    do{
        printf("%c %c %c %c\n",a[0],a[1],a[2],a[3]);
    }while(next_permutation(a,a+3));
    //还有prev_permutation()

2.2 如果是n个元素,排列k(k<n)个位置

也可以使用上面的next_permutation()但是需要除以(n-k)!

3. 组合,Cn^k类的问题

3.1 借助排列函数

使用上面的next_permutation(),但是需要除以(n-k)!*k!

3.2 使用0/1和next_permutation

查看另一篇博客即可

4. 枚举每一种可能之类的问题

比如a,b,c,d四个元素,可能取0个,可能取1个,直到可能全部都取
这里可以借助位运算符实现枚举
总共n个元素,那么一定有2^n种可能性,可以为1<<n,对于每一个数字,都进行>>x&1运算即可存入数组,表示枚举的结果

基本转换

  1. 字符串转数字
int main(){
  int a;float b;long c;
  a=atoi("321");
  b=atof("3.14125");
  c=atol("56722183");
  //如果是字符串s,需要s.data()
  printf ("%d,%f,%d",a,b,c);
  return 0;
}
  1. 数字转字符串
int main(){
  char a[10],b[10],c[10];
  sprintf(a, "%d", 32);
  sprintf(b, "%f", 3.1415);
  sprintf(c, "%d", 567283);
  string str(a);
  puts(a);
  printf("%s\n%s\n%s\n",a,b,c);
  return 0;
}
  1. 进制转换
//函数原型:
char*itoa(int value,char*string,int radix);
  1. strlen(char *)
    用于计算字符数组的长度,遇到\0就结束了

初始化

  1. 全局变量,初始化默认为0或空字符串
  2. 如果将大数组进行初始化为-1,使用memset
#include<memory.h>
using namespace std;
int a[100][100];
int main(){
    memset(a,-1,sizeof(a));
    printf("%d",a[1][2]);

    return 0;
}

因为是按照字节进行初始化的,所以最好要么是-1(每一字节是11111111)或者0,如果是初始化为1,那么上面数组中每个元素都是16843009,因为(00000001 00000001 00000001 00000001=16843009)
3. memset INF

  • 0x3f3f3f3f的十进制是1061109567,也就是10^ 9级别的(和0x7fffffff一个数量级),而一般场合下的数据都是小于10^9的,所以它可以作为无穷大使用而不致出现数据大于无穷大的情形。

  • 另一方面,由于一般的数据都不会大于10^9,所以当我们把无穷大加上一个数据时,它并不会溢出(这就满足了“无穷大加一个有穷的数依然是无穷大”),事实上0x3f3f3f3f+0x3f3f3f3f=2122219134,这非常大但却没有超过32-bit int的表示范围,所以0x3f3f3f3f还满足了我们“无穷大加无穷大还是无穷大”的需求。

  • 最后,0x3f3f3f3f还能给我们带来一个意想不到的额外好处:如果我们想要将某个数组清零,我们通常会使用memset(a,0,sizeof(a))这样的代码来实现(方便而高效),但是当我们想将某个数组全部赋值为无穷大时(例如解决图论问题时邻接矩阵的初始化),就不能使用memset函数而得自己写循环了(写这些不重要的代码真的很痛苦),我们知道这是因为memset是按字节操作的,它能够对数组清零是因为0的每个字节都是0,现在好了,如果我们将无穷大设为0x3f3f3f3f,那么奇迹就发生了,0x3f3f3f3f的每个字节都是0x3f!所以要把一段内存全部置为无穷大,我们只需要memset(a,0x3f,sizeof(a))

  • const int INF=0x3f3f3f3f

  1. memcpy
  • void * memcpy(void *dst, void *src, int length);
  • 其功能为将src地址上长度为length字节的数据,复制到dst上
  1. 优化
#pragma GCC optimize(2)
  1. 如果数据太大
    最保险的方式是将所有数值设为long long
long long ans=50000*50000;
//最终结果为负数,这就是数据不全设置为long long 造成的隐患!

搜索方面注意的问题

dfs

  • 设置终止条件
  • 设置当前状态
  • 设置下一个搜索的循环

对于当前的状态,仔细考虑如果出栈之后到底是清除状态还是保留已搜索状态,这对程序的运行时间有重要影响

bfs

  • 队列记得清空
  • use表记得清空,记得刚把元素放入队列就更新,特别是第一个
  • 记得设置flag,万一循环完之后也没结果这种情况要考虑

逗比错误集合

  1. 判断质数的时候0 <i <sqrt(n) 应该是<=
  2. 写并查集合并结点只合并子节点
  3. 忘了清空栈,队列,容器
  4. 没注意题目输出要求到80个元素就换行
  5. 在for循环里初始化后再赋值,应该在外面初始化
  6. 审题错了,想当然以为是从每个路径中最长边中取最小,结果应该是从每个路径中最短边中取最大
  7. 全局变量有一个为double结果定义成了int,结果导致vector莫名其妙的size变得很大
  8. 把不同的变量意义看反了,计算的时候变量位置错了
  9. 为了让图的i,j对齐,让输入的from,to 都减了1,但是把cost也给减了1
  10. 循环里满足条件之后忘了加break
  11. 取模的时候没有考虑周全
  12. 以后for循环都给我他妈的打括号

最短路

  1. 对于最短路的解法:对于每一个点来说,都会有一个值,我每次循环都是尽可能让连接我的点的值加上边的权重最小,也就是说
    不断的更新d[to]=min(d[to],d[from]+cost)
  2. 对于压路机问题,对于每一个点来说,是让自己的值尽量为连接我的点与边的权重之间的最大值,因为肯定是能连上的,所以就尽可能多搬一些重量,也就是说
    不断的更新d[to]=max(d[to],min(d[from],cost))
  • 对于d[from],意味着我是以最大的代价成功抵达的,但是我要向到达d[to],如果cost比我大还好说,听我的,要是cost比我小,我就得听cost的
  • 对于d[to]来说,既然能够连接到我,我自然得选择代价最大的
  1. 反转矩阵的意义在于:我从起点s找到了其它点a,b,c……的最短路,那么如何找到从a到s,从b到s,从c到s……的最短路呢?我跑一次dj算法的话,得到的是一个数组,存储了从s到其它点的最短路径,如果我反转矩阵再跑一次,得到的便是从a到s,从b到s,从c到s……这一系列的最短路径集合!然而如果不反转矩阵的话,我得对于a点跑一次dj算法,对于b点跑一次dj算法,对于c点跑一次dj算法……这和Floyd算法就没啥区别了,明明可以使用2次dj算法解决的问题,我使用了V(顶点数)次,自然花费的时间就长了
  2. bellman-ford算法应该循环n-1次就结束了,如果第v次仍然更新那么有负的环,而不是循环n次判断n+1次
  3. bidirectional双向的、unidirectional单向的、monodirectional单向的

图相关

  1. dj算法如果超时的话,要使用邻接表存储边
  2. int 类型的5000*5000数组占用内存大小约为100M

关于计数

如果统计的是某个元素出现的次数,如果这个元素可以枚举(比如字符出现的次数,长度为x的木棒出现的次数),可以使用“桶”进行存储,即:
将所有可能出现的元素用数组代表,数组脚标代表这个元素,数组内容代表这个元素出现的次数,如果没有出现就是0

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值