编程比赛常用技巧总结

3 篇文章 0 订阅
2 篇文章 0 订阅
本文总结了算法比赛中常用的输入输出优化技巧,如使用ios::sync_with_stdio(false)关闭缓冲,getline读取字符串,以及设置输出格式。此外,还详细介绍了快速幂、最短路、并查集等核心算法,并提供了二叉树建模及结构体重载小于号的示例。这些技巧对于提升算法比赛的解题效率至关重要。
摘要由CSDN通过智能技术生成

我这里的编程比赛主要指的是算法类的比赛,例如蓝桥杯,天梯赛,CCF之类的比赛。

为了备战天梯赛、蓝桥杯而写的一个总结。

输入输出

加快输入输出

ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);

cin,cout之所以效率低,是因为先把要输出的东西存入缓冲区,再输出,导致效率降低,而这段语句可以来打消iostream的输入输出缓存,可以节省许多时间,使效率与scanf与printf相差无几(但是好像还是scanf、printf比较快)

读入一行字符串

getline(cin,str)

常用输出格式控制

用来控制保留几位小数

setiosflags(ios::fixed) 控制是否是小数
setprecision(2)控制保留几位小数
cout<<setiosflags(ios::fixed)<<setprecision(2)<<e<<"%";

设置宽度 及填充对应字符

setw(5)<<setfill('0')

比赛常用算法

四舍五入

如果忘记了四舍五入的函数的话

int r(double a)
{
	int b;
	if(a>0)
	{
		return (a*2+1)/2;
	}
	else
	{
		return (a*2-1)/2;
	}
}

绝对值

fabs()//用于求浮点数绝对值
abs()//用于求整形的绝对值

快速幂算法

 求 m^k mod p,时间复杂度 O(logk)。
 k相当于转成2进制,根据最后以为判断是否应该乘
int qmi(int m, int k, int p)
{
    int res = 1 % p, t = m;
    while (k)
    {
        if (k&1) res = res * t % p;
        t = t * t % p;
        k >>= 1;
    }
    return res;
}

最短路算法

int g[N][N];  // 存储每条边
int dist[N];  // 存储1号点到每个点的最短距离
bool st[N];   // 存储每个点的最短路是否已经确定

// 求1号点到n号点的最短路,如果不存在则返回-1
int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);//注意是赋值的为0x3fmemset赋值是按字节赋值
    dist[1] = 0;

    for (int i = 0; i < n - 1; i ++ )//第一个点已经找到所以循环n-1
    {
        int t = -1;     // 在还未确定最短路的点中,寻找距离最小的点
        for (int j = 1; j <= n; j ++ )
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;

        // 用t更新其他点的距离
        for (int j = 1; j <= n; j ++ )
            dist[j] = min(dist[j], dist[t] + g[t][j]);

        st[t] = true;
    }

    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}

并查集

(1)朴素并查集:

    int p[N]; //存储每个点的祖宗节点

    // 返回x的祖宗节点
    int find(int x)
    {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }

    // 初始化,假定节点编号是1~n
    for (int i = 1; i <= n; i ++ ) p[i] = i;

    // 合并a和b所在的两个集合:
    p[find(a)] = find(b);


(2)维护size的并查集:

    int p[N], size[N];
    //p[]存储每个点的祖宗节点, size[]只有祖宗节点的有意义,表示祖宗节点所在集合中的点的数量

    // 返回x的祖宗节点
    int find(int x)
    {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }

    // 初始化,假定节点编号是1~n
    for (int i = 1; i <= n; i ++ )
    {
        p[i] = i;
        size[i] = 1;
    }

    // 合并a和b所在的两个集合:
    size[find(b)] += size[find(a)];
    p[find(a)] = find(b);


(3)维护到祖宗节点距离的并查集:

    int p[N], d[N];
    //p[]存储每个点的祖宗节点, d[x]存储x到p[x]的距离

    // 返回x的祖宗节点
    int find(int x)
    {
        if (p[x] != x)
        {
            int u = find(p[x]);
            d[x] += d[p[x]];
            p[x] = u;
        }
        return p[x];
    }

    // 初始化,假定节点编号是1~n
    for (int i = 1; i <= n; i ++ )
    {
        p[i] = i;
        d[i] = 0;
    }

    // 合并a和b所在的两个集合:
    p[find(a)] = find(b);
    d[find(a)] = distance; // 根据具体问题,初始化find(a)的偏移量

二叉树建树

例如:
输入前序遍历、中序遍历
输出层序遍历
一直操作左右两边便好

#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#define tree node*
using namespace std;
struct node{
	int d;
	tree l;
	tree r;
};
const int N=40;
int z[N],q[N],n;
tree Build(int ql,int qr,int zl,int zr)
{
	if(ql>qr) return NULL;
	tree root=new node;
	root->d=q[ql];
	int k;
	for(int i=zl;i<=zr;i++)
	{
		if(z[i]==q[ql])
		{
			k=i;
		}
	}
	int leftnum=k-zl;
	root->l=Build(ql+1,ql+leftnum,zl,k-1);
	root->r=Build(ql+leftnum+1,qr,k+1,zr);
	return root;
}
void cen(tree t)
{
	int i=0;
	queue<tree> q;
	q.push(t);
	while(!q.empty())
	{
		tree f=q.front();
		i++;
		if(i==n)
		{
			cout<<f->d;
		}
		else
		{
			cout<<f->d<<" ";
		}
		q.pop();
		if(f->r!=NULL)
		{
			q.push(f->r);
		}
		if(f->l!=NULL)
		{
			q.push(f->l);
		}
	}
}
int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>z[i];
	}
	for(int i=0;i<n;i++)
	{
		cin>>q[i];
	}
	tree t=Build(0,n-1,0,n-1);
	cen(t);
}

结构体重载小于号

用于设置map<node,int> 类型的数据

bool operator<(const People &t) const
	{
		if(time!=t.time) return time<t.time;
		else return idx<t.idx;
	}

数据结构

默认是大根堆
想要转成小根堆还有是读入的数转化为负数,输出的时候输出正数就好。

priority_queue, 优先队列,默认是大根堆
    size()
    empty()
    push()  插入一个元素
    top()  返回堆顶元素
    pop()  弹出堆顶元素
    定义成小根堆的方式:priority_queue<int, vector<int>, greater<int>> q;
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

void printHeap(vector<int> &v){
    for(vector<int>::iterator it= v.begin();it!=v.end();++it){
        cout<< *it <<" ";
    }
    cout<<"\n"<<endl;
}

int main()
{
    vector<int> min={10,30,22,6,15,9};

    //建立小顶堆
    make_heap(min.begin(), min.end(), greater<int>());
    printHeap(min);//6 10 9 30 15 22

    //插入元素
    min.push_back(20);
    push_heap(min.begin(),min.end(), greater<int>());//该算法前提:必须在堆的条件下
    printHeap(min); //6 10 9 30 15 22 20   仍为小顶堆

    //删除堆顶元素
    pop_heap(min.begin(),min.end(), greater<int>());
    printHeap(min);//9 10 20 30 15 22 6  不为小顶堆 这个pop_heap操作后,实际上是把堆顶元素放到了末尾
    min.pop_back();//这才彻底在底层vector数据容器中删除
    printHeap(min);//9 10 20 30 15 22  仍为小顶堆

    //堆排序  保持greater,小顶堆,得到的是降序
    sort_heap(min.begin(),min.end(), greater<int>());//试了用less,结果杂乱无章
    printHeap(min);//30 22 20 15 10 9 注意结果是降序的哦!!!其实是调用了很多次pop_heap(...,greater..),每一次都把小顶堆堆顶的元素往末尾放,没放一次end迭代器减1

    return 0;
}

pair

pair<int, int>
    first, 第一个元素
    second, 第二个元素
    支持比较运算,以first为第一关键字,以second为第二关键字(字典序)

vector

vector, 变长数组,倍增的思想
    size()  返回元素个数
    empty()  返回是否为空
    find(v.begin(), v.end(), a) ,如果能在容器v中不能寻找到a,则返回v.end()
    clear()  清空
    front()/back()
    push_back()/pop_back()
    begin()/end()
    []
    支持比较运算,按字典序

set, map, multiset, multimap, 基于平衡二叉树(红黑树),动态维护有序序列

size()
    empty()
    clear()
    begin()/end()
    ++, -- 返回前驱和后继,时间复杂度 O(logn)

    set/multiset
        insert()  插入一个数
        find()  查找一个数
        set_name.find(element) 
        count()  返回某一个数的个数
        erase()
            (1) 输入是一个数x,删除所有x   O(k + logn)
            (2) 输入一个迭代器,删除这个迭代器
        lower_bound()/upper_bound()
            lower_bound(x)  返回大于等于x的最小的数的迭代器
            upper_bound(x)  返回大于x的最小的数的迭代器
    map/multimap
        insert()  插入的数是一个pair
        erase()  输入的参数是pair或者迭代器
        find()
        []  注意multimap不支持此操作。 时间复杂度是 O(logn)
        lower_bound()/upper_bound()

deque

效率低

size()
    empty()
    clear()
    front()/back()
    push_back()/pop_back()
    push_front()/pop_front()
    begin()/end()
    []

stack

stack,size()
    empty()
    push()  向栈顶插入一个元素
    top()  返回栈顶元素
    pop()  弹出栈顶元素

queue

queue, 队列
size()
empty()
push() 向队尾插入一个元素
front() 返回队头元素
back() 返回队尾元素
pop() 弹出队头元素

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值