PAT记录

判断素数

HDU1059
求一个数字的质因子之积时,只需要考虑小于等于根号n的质因子,但是最后剩下的可能还是个质数,所以要格外考虑下

bool isPrime(int x){
    if(x<=1)
        return false;
    for(int i=2; i<=int(sqrt(x*1.0)); i++){
        if(x % i == 0)
            return false;
    }
    return true;
}

最大公约数gcd 辗转相除法

int gcd(long long a, long long b){
    return b == 0 ? abs(a) : gcd(b, a%b);
}

最小公倍数

int lcm(int a, int b) {
	return a * b / gcd(a, b); 
}

四则运算

https://pintia.cn/problem-sets/994805342720868352/problems/994805378443755520

//定义分子分母
struct fraction{
    ll up, down;
}a, b;

//gcd最简化
fraction reduction(fraction res){
    if(res.down<0){  //保证分母是正数
        res.up = -res.up;
        res.down = -res.down;
    }
    if(res.up == 0)
        res.down = 1;
    else{
        int t = gcd(abs(res.up), abs(res.down));
        res.up /= t;
        res.down /= t;
    }
    return res;
}
//分数加法
fraction add(fraction f1, fraction f2){
    fraction res;
    res.up = f1.up * f2.down + f2.up * f1.down;
    res.down = f1.down * f2.down;
    return reduction(res);
}
//输出形式
void showResult(fraction res){
    res = reduction(res);
    if(res.up<0)
        cout << "(";
    if(res.down == 1)
        cout << res.up;
    else if(abs(res.up) > res.down)
        cout << res.up/res.down << " " << abs(res.up)%res.down << "/" << res.down;
    else
        cout << res.up << "/" << res.down;
    if(res.up<0)
        cout << ")";
}

将n按照d进制逆序

while(n){
    sum = sum * d + n % d;
    n = n / d;
}

结构体的定义

struct record{
    char name[25];
    int month, dd, hh, mm;
    bool status;
}rec[maxn], temp;

排序cmp

bool cmp(record a, record b){
    int s = strcmp(a.name, b.name);
    if(s != 0)
        return s < 0; //优先按照姓名字典序从小到大排序
    else if(a.month != b.month) //按照月份排序
        return a.month < b.month;
    else if(a.dd != b.dd)
        return a.dd < b.dd;
    else if(a.hh != b.hh)
        return a.hh < b.hh;
    else
        return a.mm < b.mm;
}

//比较字符串或者是char数组时,用strcmp
return strcmp(a.id,b.id)<0;

//使用方法
sort(rec, rec+N, cmp);

枚举问题

2^n种情况(熄灯问题)
直到guess()==false退出枚举

while(guess()){
    press[1][1]++;
    int k=1;
    while(press[1][k] > 1){
        press[1][k] = 0;
        k++;
        press[1][k]++;
    }
}

火柴棍等式问题(洛谷P1149)
给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?

https://www.cnblogs.com/dongq/p/4162394.html

首先确定每个数字所用的火柴棍树木,用一层递归一层循环枚举一次,确定两个加数的值,算出和,进行进行判断,若符合条件则进行记录。
(题目说明最多24根火柴棍,减去+和=,还剩20根,因此数据不会超过1000)

大整数加法

string add(string s1,string s2)  // 加
{
    int i,j,k,t;
    string sum;
    t=0;
    k=0;
    if(s2.size()>s1.size())
    {
        s1.swap(s2);
        k=1; //标记是否s1,s2交换;保证s2长度不大于s1
    }
    for(i=0;i<s2.size();i++)
    {
        sum+=(s1[s1.size()-1-i]-'0'+s2[s2.size()-1-i]-'0'+t)%10+'0';  //从末位开始逐位做加法,t表示是否进位
        if((s1[s1.size()-1-i]-'0'+s2[s2.size()-1-i]-'0'+t)>=10)
            t=1;
        else t=0;
    }

    if(s1.size()==s2.size() && t==1)
        sum+='1';
    else
    {
        for(j=s1.size()-1-i;j>=0;j--)
        {
            sum+=(s1[j]-'0'+t)%10+'0';
            if(s1[j]-'0'+t>=10)
                t=1;
            else t=0;
        }
        if(t==1)
            sum+='1';
    }
    reverse(sum.begin(),sum.end());
    return sum;
}

大整数减法

string sub(string s1,string s2)   // 减
{
    int flag=0,i;
    if(s1.size()<=s2.size())
    {
        if(s2.size()>s1.size())
            flag=1;
        else
        {
            for(i=0;i<s1.size();i++)
            {
                if(s1[i]>s2[i])
                    break;
                else if(s1[i]<s2[i])
                {
                    flag=1;
                    break;
                }
            }
        }
    }
    //保证s2小于等于s1
    if(flag==1)
        s1.swap(s2);
    string ans;
    reverse(s1.begin(),s1.end());
    reverse(s2.begin(),s2.end());
    for(i=0;i<s1.size();i++)
    {
        if(i>=s2.size())
            s2+='0';
        ans+=s1[i]-s2[i]+'0';
        if(s1[i]<s2[i])
        {
            ans[i]+=10;
            s1[i+1]-=1;
        }
    }
    reverse(ans.begin(),ans.end());
    for(i=0;i<ans.size();i++)
    {
        if(*ans.begin()=='0')ans.erase(ans.begin());
        else break;
    }
    if(flag==1)
        ans.insert(0,"-");
    return ans.size()==0?"0":ans;
}

大整数乘法

string mul(string s1,string s2)    // 乘
{
    int i,j,t;
    vector<int> num1,num2,ans;
    string s;
    //倒过来放算的时候比较方便
    for(i=s1.size()-1;i>=0;i--)
    {
        num1.push_back(s1[i]-'0');
    }
    for(i=s2.size()-1;i>=0;i--)
    {
        num2.push_back(s2[i]-'0');
    }

    //按照平常的计算方式计算
    for(i=0;i<num2.size();i++)
        for(j=0;j<num1.size();j++)
        {
            if(i+j>=ans.size())
                ans.push_back(num1[j]*num2[i]);
            else 
                ans[i+j]+=num1[j]*num2[i];
        }
    
    //解决进位问题
    t=0;
    for(i=0;i<ans.size();i++)
    {
        ans[i]+=t;
        t=ans[i]/10;
        ans[i]%=10;
    }
    if(t!=0)
        ans.push_back(t);
    reverse(ans.begin(),ans.end());
    for(i=0;i<ans.size();i++)
        s+=ans[i]+'0';
    return s;
}

将字符串转化为double,整数转为字符串

string n;
double x = atof(n.c_str())

//整数转为字符串
int n;
string m = to_string(n);

读入未知长度以空格区分的一行数据

//例如 * + 11.0 12.0 + 24.0 35.0
string temp;
while(cin >> temp){
     n[index++] = temp;
     char ch = getchar();//通过getchar()来判断最后输入回车符结束
     if(ch == '\n')
        break;
}

优先队列

队首元素一定是当前队列中优先级最高的那一个

priority_queue<int> q;
priority_queue<double, vector<double>, greater<double> > q;
//默认从大到小
//greater从小到大
//> >之间必须要有空格
struct node{
	int x,y;
	friend bool operator<(node a,node b)
	{
		return a.x>b.x;//按x从小到大排 
	}
};
priority_queue<node>q4;

中缀转为后缀表达式(含!)

string s;
vector<char> sta;
stack<char> temp;
getline(cin, s);
sta.clear();
for(int i=0; i< s.size(); i++){
   if(s[i] == ' ')
       continue;
   if(s[i] == 'V' || s[i] == 'F')
       sta.push_back(s[i]);
   else{
       if(s[i] == '('){
           temp.push(s[i]);
       }
       else if(s[i] == ')'){
           char x = temp.top();
           sta.push_back(x);
           temp.pop();
           temp.pop();
       }
       else if(s[i] == '!'){
           temp.push(s[i]);
       }
       else if(s[i] == '|' || s[i] == '&'){
           if(temp.empty())
               temp.push(s[i]);
           else{
               while(temp.top() == '|' || temp.top() == '&' || temp.top() == '!'){
                   sta.push_back(temp.top());
                   temp.pop();
                   if(temp.empty())
                       break;
               }
               temp.push(s[i]);
           }
       }
   }
}
for(int i=0; i<temp.size(); i++){
   sta.push_back(temp.top());
   temp.pop();
}

KMP字符串匹配算法

用string存储有时会超时,可用char[]数组代替

//将字符串输入到s中,并且增加s[0]=k,输入从s[1]开始
char s[100];
scanf("%s", s+1);
    s[0] = 'k';
//求输入到数组中的字符串长度
int len = strlen(s);
//nextval
void cal_nextval(string t){
    int i=1, j=0;
    nextval[1] = 0;
    while(i <= t.length()){
        if(j == 0 || t[i] == t[j]){
            i++;
            j++;
            if(t[i] != t[j])
                nextval[i] = j;
            else
                nextval[i] = nextval[j];
        } else
            j = nextval[j];
    }
}

//KMP

int kmp(string s, string t){
    cal_nextval(t);
    int i=1, j=1;
    int c = 0;
    while(i <= s.length() && j <= t.length()){
        if(j==0 || s[i] == t[j]){
            i++;
            j++;
        } else
            j = nextval[j];
        if(j>t.length()){
            c++;
            j=nextval[j];
        }
    }
    return c;
}

kmp next 变形

char s[1005];
char t[1005];
int nextval[1005] = {0};

void get_next(int len_t){
    int i=0, j=-1;
    nextval[0] = -1;
    while(i < len_t){
        if(j == -1 || t[i]==t[j]){
            i++;j++;
            nextval[i] = j;
        } else
            j = nextval[j];
    }
}

int kmp(int len_s, int len_t){
    get_next(len_t);
    int count=0;
    int i=0, j=0;
    while(i < len_s){
        if(j==-1 || s[i] == t[j]){
            i++;j++;
        }
        else
            j=nextval[j];
        if(j>=len_t){
            j=0;
            count++;
        }
    }
    return count;
}

int main(){
    while(cin >> s){
        if(s[0] == '#' && strlen(s) == 1)
            break;
        cin >> t;
        int len_s = strlen(s);
        int len_t = strlen(t);
        cout << kmp(len_s, len_t) << endl;

    }
}

map的使用

map的遍历顺序与输入顺序是不一致的,内部是红黑树机制,按照key自动排序

map<string, string> m;
m[b] = a; //赋值或者取值
//map初始化
map<int, string>m = {{0,"ling"}, {1,"yi"}}
//迭代
map<string, string>::iterator iter;
for(iter=m.begin(); iter != m.end(); iter++)
	cout << iter->first << " " << iter->second << endl;

//迭代法二
for(auto iter=m.begin(); iter != m.end(); iter++)

list的使用

list<int> lit[10005];
//插入
lit[id1].push_back(id2);
//合并两个list
lit[id1].merge(lit[id2]);
//去重,unique只能去重相邻元素
lit[id1].unique();
//list不能按下标取值,只能用迭代器
list<int>::iterator it;
int i=0;
for(it=lit[id1].begin();it!=lit[id1].end();++it)
	cout << *it << endl;

前序和中序构造二叉链表

struct node{
    int data;
    node *lc, *rc;
}*N;

node * PreInCreate(int prei, int prej, int ini, int inj){
    node *root = new node;
    root->data = pre[prei];
//    cout << root->data << " ";
    int i;
    for(i=ini; in[i]!=root->data; i++);
    int llen = i-ini;
    int rlen = inj-i;
    if(llen)
        root->lc = PreInCreate(prei+1, prei+llen, ini, i-1);
    else
        root->lc = NULL;
    if(rlen)
        root->rc = PreInCreate(prej+i-inj+1, prej, i+1, inj);
    else
        root->rc = NULL;
    return root;
}

node *TT = new node;
TT = PreInCreate(1, k, 1, k);

数组置为inf

#define inf 0x3f3f3f
//int e[1000][1000], dis[1000];
fill(e[0], e[0] + 510 * 510, inf);
fill(dis, dis + 510, inf);
memset(dis, 0, sizeof(dis));

❗️❗️double类型的e[][]不能用memset置为inf,需用fill
因为memset函数按照字节填充,所以一般memset只能用来填充char型数组,(因为只有char型占一个字节)。如果填充int型数组,只能填充0、-1 和 inf(正负都行)。因为00000000 = 0,-1同理,如果我们把每一位都填充“1”,会导致变成填充入“11111111”。如果我们将inf设为0x3f3f3f3f,0x3f3f3f3f的每个字节都是0x3f!所以要把一段内存全部置为无穷大,我们只需要memset(a,0x3f,sizeof(a))。无穷小可以将-INF设为0x8f。
而fill函数可以赋值任何值。

Cin Cout 超时

一、使用scanf, printf代替

char name[10];
scanf("%s", name);
//可以直接strcmp(name, "xxxx")==0判断

实在是要用string
!!!

node.name.resize(10);
scanf("%s", &node.name[0]);//这样输入会自动在不足resize的位置以“\0”填充,所以不能直接跟给定的“xxx”进行==比较
printf("%s", node.name.c_str());
//加上.c_str()之后,会把后面的"\0"去掉

!!!
char[]数组和string比较字符串时有区别
char[]
return (strcmp(a.name, b.name) < 0);
string
return a.name < b.name;

vector初始化

vector<int>v(n);
//这样就可以直接给v[i]赋值,如果不初始化(不加(n))只能push_back

关于string
可以用s.substr(1,3)代表子串,从1开始的3位

二、直接cin >> node[i].ch,也可能会超时,先cin到临时变量,再存到node里面去

三、map<string, vector > stu;
👆比👇快
map<string, int> stu;
vector course;
放在

struct stu{
    char id[8], name[9];
    int score;
}student;
scanf("%s%s%d", student.id, student.name, &student.score);

unordered_map比map快

未在map里的东西,直接用时等于0

图————求两点间的最短距离,最短距离一致则找最小花费 dijskra+dfs模板

多起点,多终点问题可以看作超级源点,比如把某点看作超级源点,多个起点到这个源点的距离看作0即可

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f

//图————求两点间的最短距离,最短距离一致找最小花费
//dijskra+dfs, dijskra解决最短路径,dfs解决花费最少问题

//e代表两点间距离,dis代表start到该点的最短路径,cost代表两点间花费
int e[510][510], dis[510], cost[510][510];
int n, m, s, d;
//pre代表从起点到该点的路径
vector<int> pre[510];
//path代表最终路径,temppath是临时变量
vector<int> path, temppath;
//visit代表该点是否被访问过
bool visit[510];
//mincost代表最小花费
int mincost = inf;

void dfs(int v){
    temppath.push_back(v);
    //更新路径,找到花费最少的
    if(v == s){
        int tempcost = 0;
        for(int i=temppath.size()-1; i>0; i--){
            int id=temppath[i], nextid=temppath[i-1];
            tempcost += cost[id][nextid];
        }
        if(tempcost < mincost){
            mincost = tempcost;
            path = temppath;
        }
        //
        temppath.pop_back();
        return;
    }
    for(int i=0; i<pre[v].size(); i++)
        dfs(pre[v][i]);
    temppath.pop_back();
}


int main(){
    fill(e[0], e[0]+510*510, inf);
    fill(dis, dis+510, inf);
    cin >> n >> m >> s >> d;
    for(int i=0; i<m; i++){
        int a, b;
        cin >> a >> b;
        cin >> e[a][b];
        e[b][a] = e[a][b]; //考虑两个点之间存在多条路,先判断输入的距离是否小于现在的e[a][b]
        cin >> cost[a][b];
        cost[b][a] = cost[a][b];
    }
    pre[s].push_back(s);
    dis[s] = 0;
    //设置dis[s]=0,从出发点开始算
    for(int i=0; i<n; i++){
        //u代表当前最近的点
        int u=-1, mmin=inf;
        for(int j=0; j<n; j++){
            //从所有没被访问过的点中找出距离最近的点加入集合中
            if(visit[j] == false && dis[j] < mmin){
                u=j;
                mmin = dis[j];
            }
        }
        //没有多余连通的点
        if(u==-1)
            break;
        visit[u] = true;
        //以u为起始,更新整个未访问过的集合,pre存放与该节点最近相连的1个或者n个节点
        for(int v=0; v<n; v++){
            if(visit[v]==false && e[u][v]!=inf){
                if(dis[v] > dis[u]+e[u][v]){
                    dis[v] = dis[u]+e[u][v];
                    pre[v].clear();
                    pre[v].push_back(u);
                }
                else if(dis[v] == dis[u]+e[u][v]){
                    pre[v].push_back(u);
                }
            }
        }
    }
    dfs(d);
    for(int i=path.size()-1; i>=0; i--)
        cout << path[i] << " ";
    cout << dis[d] << " " << mincost << endl;
}

将数组置为inf

int e[510][510];
fill(e[0], e[0]+510*510, inf);

int dis[510];
fill(e, e+510, inf);

将string全部映射为int

PAT 1034 Head of a Gang
dfs求连通域个数,图的节点是string类型,需要转化为int类型

map<int , string> intTostring;
map<string, int> stringToint;
//name1已有对应的string
if(stringToint.find(name1) != stringToint.end())
	id1 = stringToint[name1];
//第一次出现的string,找一个新的数字跟他对应
else{
    stringToint[name1] = now_person;
    intTostring[now_person] = name1;
    id1 = now_person;
    now_person++;
}

二分查找(nlogn)

PAT 1044 Shopping in Mars
递增数组,从p开始查找不小于k且最接近k的数字区间段存入res
总长度为n
数组sum

void search(int p){
    int start = p, end = n;
    while(start < end){
        int mid = (start+end)/2;
        if(sum[mid] - sum[p-1] >= k)
            end = mid;
        else
            start = mid+1;
    }
    int temp = sum[start] - sum[p-1];
    if(temp >= k && temp <= mmax){
        if(temp < mmax){
            mmax = temp;
            res.clear();
        }
        res.push_back(p);
        res.push_back(start);
    }

}

有回溯的dfs

寻找符合条件的多条路径,此时需要回溯
PAT1053 Path of Equal Weight (30 分)
自己一次过做出来的30分题,还有点小开心的!

//p为路径,ss为路径上的权重值,visit为是否访问
void dfs(int t){
    visit[t] = 1;
    ss += weight[t];
    p.push_back(t);
    if(node[t].size() == 0 && ss == s){
        vector<int> temp;
        for(int k=0; k<p.size(); k++){
            temp.push_back(weight[p[k]]);
        }
        final.push_back(temp);
        //找到一条路径,以下条件需要恢复环境
        p.pop_back();
        ss -= weight[t];
        visit[t] = 0;
        return;
    }

    for(int i=0; i<node[t].size(); i++){
        if(visit[node[t][i]] == 0)
            dfs(node[t][i]);
    }
    //这些条件后面的路径还会用到,所有需要恢复环境
    visit[t] = 0;
    ss -= weight[t];
    p.pop_back();
}

基础模板
//hdu 1548

void dfs(int k){
	//return的条件
    if(press >= mmin)
        return;
    if(k == b){
        if(press < mmin)
            mmin = press;
        return;
    }
    //需要回溯的两个标记,vis和press
    vis[k] = true;
    press++;
    //dfs语句
    if(k+lift[k] <= n && vis[k+lift[k]] == false) {
        dfs(k + lift[k]);
    }
    if(k-lift[k] >= 1 && vis[k-lift[k]] == false) {
        dfs(k - lift[k]);
    }
    //两个变量回溯
    press--;
    vis[k] = false;
}

set和multiset

set的含义是集合,它是一个有序的容器,里面的元素都是排序好的,支持插入,删除,查找等操作,就像一个集合一样。所有的操作的都是严格在logn时间之内完成,效率非常高。 set和multiset的区别是:set插入的元素不能相同,但是multiset可以相同

set中find和count的时间复杂度都为logn
求两个数组的交集数字个数

set 迭代器输出用 *iter
默认按照递增的顺序排列

int nc = 0;
for(auto it = st[id1].begin();it != st[id1].end();it++){
   if(st[id2].find(*it) != st[id2].end()) 
       nc++;//使用find,去第二个数列中查找该数出现过没有
} 

求某数化为二进制后有多少位为1

int FF(int i){
    int x=0;
    while(i){
        if(i & 1){
            x++;
        }
        i >>= 1;
    }
    return x;
}

中序序列==>顺序输出

将有序序列变为完全二叉树的中序序列存储

int num[2001], res[2001];
int n, k=0;
//num存储现有的有序序列,res存储中序序列,n=size
void inorder(int t){
    if(t >= n)
        return;
    inorder(t*2+1);
    res[t] = num[k++];
    inorder(t*2+2);
}
//调用
inorder(0);

使序列有序的最少交换次数

n = 数列元素个数 - 循环节个数

https://blog.csdn.net/lfb637/article/details/86653121

仅允许在相邻两元素间交换,求最少交换次数
即求逆序对==>归并排序算法可求

https://blog.csdn.net/lfb637/article/details/78309507

atoi stoi

将数字字符串转为int
atoi不会做范围检查,stoi会做范围检查,超出int范围报错runtime error
stoi(s1);
atoi(s1.c_str());

往字符串中插入0
s.insert(0, 4-s.length(), ‘0’);

边界条件

1、字符串比较时考虑字符串的长度

易忽略的点

1、C++中int和long long特别容易被忽略的点,在做乘法的时候即使单个变量在int范围内,如果乘积超了int,也需要将乘数定义为longlong 否则会出错
long double------>printf("%.2Lf", x)
2、vector可以直接使用=号来判断两个数组是否相同
3、数据为10^9时,inf要定义成0x3f3f3f3f,否则真的会死掉!
4、实在过不去,把数组开大点
5、int 10位,2^32次-1;long long 19位,2的63次-1
6、NULL——int类型默认为0,bool类型默认为false
7、int visit[205] = {0};像这样的定义必须在循环里重新赋值为0,用fill或者for循环,否则编译器不同可能会报错
8、二维数组开到10的5次乘10的5次会内存超限,用vector,map等巧妙化解
9、有关树的题目,左右子树要乘2,所以数组大小要开到2倍以上
10、题目说的是每两组数据之间输出一个空行,注意最后一组之后没有空行
11、看清楚是以什么结束输入,a pair of negative integers不是-1 -1 。(这题以为-1 -1结束输入,TLE了很久)
12、变量初始化,特别是像char这种的,1001 A+B Format因为char x没有初始化wa了

dfs、bfs基础模板

void dfs(int u, int l){
    visit[u] = 1;
    for(int i=0; i<v[u].size(); i++){
        if(visit[v[u][i]] == 0)
            dfs(v[u][i], l+1);
    }
}

三维数组求连通域——bfs

https://blog.csdn.net/qq_34649947/article/details/81213275

//表示三个方向
int xx[6] = {0,0,0,0,-1,1};
int yy[6] = {0,0,-1,1,0,0};
int zz[6] = {-1,1,0,0,0,0};
struct node{
    int x, y, z;
};
queue<node> q;

排序

当题目中涉及到插入排序,归并排序等,不需要真的去实现,用sort就可以

并查集!!

https://blog.csdn.net/zjy_code/article/details/80634149

例题:

1、PAT 1107 Social Clusters

记录每个节点的父亲节点是哪个节点,是否属于一个门派

2、 http://bailian.openjudge.cn/tm2019/F/

//初始化:初始的时候每个结点各自为一个集合,father[i]表示结点 i 的父亲结点,如果 father[i]=i,我们认为这个结点是当前集合根结点。
void init() {
    for (int i = 0; i < n; ++i) {
        father[i] = i;
    }
}
//查找:查找结点所在集合的根结点,结点 x 的根结点必然也是其父亲结点的根结点。
int get(int x) {
    if (father[x] == x) { // x 结点就是根结点
        return x;
    }
    return father[x] = get(father[x]); // 返回父结点的根结点,并另当前结点父结点直接为根结点
}
//合并:将两个元素所在的集合合并在一起,通常来说,合并之前先判断两个元素是否属于同一集合。
void merge(int x, int y) {
    x = get(x);
    y = get(y);
    if (x != y) { // 不在同一个集合
        father[y] = x;
        num[x] += num[y]; //用于计算最大的一个集合里有多少个数字
    }
}

并查集判断所有点是否处于同一个集合:遍历所有点,看getfa是否相同

//v中保存的是所有的点
int x = getfa(v[0]);
for(int i=1; i<v.size(); i++){
    if(getfa(v[i]) != x){
        hui = 1; //hui=1说明不处于一个集体
        break;
    }
}

判断是否存在回路:merge里如果fa[y] == fa[x],说明x,y已经是同一个集合里的了,如果再把他们merge就会形成回路
如果y只能由一个x到达,那么还要再增加一条 fa[y] != y

void merge(int x, int y){
    int x = getfa(x);
    int y = getfa(y);
    if(x != y)
        fa[y] = x;
    else  // x==y说明形成回路了
        hui = 1;
}

调整大顶堆

把数组中最大的数字调整到最上面,并且把下面的恢复成大顶堆的样子
因为本来就是大顶堆,只是第一个数字变了,所以影响的只是单路上的数字

//法一
void downAdjust(vector<int> &b, int low, int high) {
    int i = 1, j = i * 2;
    while(j <= high) {
        if(j + 1 <= high && b[j] < b[j + 1]) j = j + 1;
        if (b[i] >= b[j]) break;
        swap(b[i], b[j]);
        i = j; j = i * 2;
    }
}

//法2
//将元素k为根的子树进行调整
void HeadAdjust(int a[], int k, int len){
    a[0] = a[k];
    for(int i=2*k; i<=len; i*=2){
        if(i<len && a[i]<a[i+1])
            i++;
        if(a[0] >= a[i])
            break;
        else{
            a[k] = a[i];
            k=i;
        }
    }
    a[k] = a[0];
}
//构建大顶堆
void BUildmaxHeap(int a[], int len){
    for(int i=len/2; i>0; i--)
        HeadAdjust(a, i, len);
}

//堆排序
void HeapSort(int a[], int len){
	BUildmaxHeap(a, len);
	for(int i=len; i>1; i--){
		swap(a[i], a[1]); //输出堆顶元素(和堆底元素交换)
		HeadAdjust(a, 1, i-1); //调整,把剩余的i-1个元素整理成堆
	}
}

判断输入是否符合规定小数要求

PAT 1108 Finding Average

//要求判断输入是否为保留两位的小数
double temp;
char a[50], b[50];
scanf("%s", a);
sscanf(a,"%lf",&temp); //把a的值以double格式赋给temp。如果输入的不是数字,temp会继续保留之前的数字
sprintf(b,"%.2f",temp);//temp按%.2f写到b
//比较a和b是否一致即可

平衡二叉树

总结模版如下

https://blog.csdn.net/PickCake/article/details/116133191

The lowest common ancestor (LCA)最近公共祖先

1151 LCA in a Binary Tree (30 分)
不需要建树,一般性建树都会超时,或者段错误
一般会给定先序遍历和中序遍历序列
已知某个树的根结点,若a和b在根结点的左边,则a和b的最近公共祖先在当前子树根结点的左子树寻找,如果a和b在当前子树根结点的两边,在当前子树的根结点就是a和b的最近公共祖先,如果a和b在当前子树根结点的右边,则a和b的最近公共祖先就在当前子树的右子树寻找。中序加先序可以唯一确定一棵树,在不构建树的情况下,在每一层的递归中,可以得到树的根结点,在此时并入lca算法可以确定两个结点的公共祖先~

void lca(int inl, int inr, int prel, int a, int b){
    if(inl > inr)
        return;
    int inRoot = pos[pre[prel]], ain = pos[a], bin = pos[b];
    if(ain < inRoot && bin < inRoot)
        lca(inl, inRoot-1, prel+1, a, b);
    else if((ain < inRoot && bin > inRoot) || (ain > inRoot && bin < inRoot))
        printf("LCA of %d and %d is %d.\n", a, b, in[inRoot]);
    else if(ain > inRoot && bin > inRoot)
        lca(inRoot+1, inr, prel+1+(inRoot-inl), a, b);
    else if(ain == inRoot)
        printf("%d is an ancestor of %d.\n", a, b);
    else if (bin == inRoot)
        printf("%d is an ancestor of %d.\n", b, a);
}

枚举:

enum weekday {sun=1,mon,tue,wed,thu,fri,sat} day;
//从自定义的那项开始,递增1,即mon=2,tue=3
cout << tue —— 3
可以通过前面的值输出后面的值,但是若要通过后面的值输出前面的值,只能通过switch
例:
switch(k)
{
case mon:
case tue:
case wed:
case thu:
case fri: printf(“今天上班\n”); break;

case sun:
case sat:       printf("今天休息\n"); break;

default:        printf("输入有误\n"); break;

}

格式

cout << fixed << setprecision(1) << 输出保留1位小数
输入未知长度的数组:

while(cin >> n){
   //要写的代码,getchar判断放在while最后
    char ch;
    ch = getchar();
    if(ch == '\n')
        break;
}

输出true/false,可在前面加boolalpha
定义一个无穷大的数:const int INF=0x7fffffff;

输入一组数据后输入一个空行

string s;
getline(cin, s); //吃掉空行

如果要在使用过cin后面用getline读取一行,必须先getline把之前那行的换行符吃掉,再一次getline才能读入下一行

字符串前面补零

//将数字转换为字符串,并且前面补足零
char aa[10];
int a;
sprintf(aa, "%08d", a);
sprintf(bb, "%08d", b);

printf输出%

printf("%.1f%%", a);
//%%输出%

母函数递推

hdu2082、1085、1028
https://www.cnblogs.com/shentr/p/5347659.html

int f(int n)   //母函数
{
   int s[52],a[52];    //s存的是x^nd的各项系数,a是每次计算前两个括号是的结果。
   int i,j,k;
   for(i=0;i<=n;i++){ //计算之前要先把s和a初始化,a[i]为过程量每次计算时初始化为0;
      s[i]=0;
      a[i]=0;
   }
   for(i=0;i<=d[1];i++)  //d存的是每个物品的可用数量,初始化
      s[i]=1;
   for(i=2;i<=26;i++)   //一般从2开始,1已经初始化完了
   {
      for(j=0;j<=n;j++)     //j表示s[j],例i=2,j=0时,就是指x^0的系数
         for(k=0;k<=d[i]&&k*i+j<=n;k++) //表示第i个括号的第k个表达式,当i=2;k=1就x^4;
             a[k*i+j]+=s[j];//就是把系数为为i和系数为k*i*i的系数加在一起;
      for(k=0;k<=n;k++)   //把每次的结果a复制到s内;a[i]初始化为0;
      {
          s[k]=a[k];
          a[k]=0;
      }
}
   for(i=1,k=0;i<=n;i++)
      k+=s[i]; //s[i]代表属性值和为i的组合种数
   return k;
}

打表->可用于解决超时问题

hdu 1028
https://www.cnblogs.com/Taskr212/p/9560422.html

分治递推方法直接求解会超时,先将120个解求出存下来,然后直接取值输出

走迷宫

百练oj 4127
http://bailian.openjudge.cn/tm2019/C/

//百练oj 4127题解
//法一:BFS
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
typedef long long ll;

int matrix[6][6]; //输入矩阵
int vis[6][6]; //是否访问过
struct nod{
    int x, y;
    int pre;
}node[5*5+10];

int head = 0, tail = 1;
//上下左右四个方向
int locx[5] = {1, -1, 0, 0};
int locy[5] = {0, 0, 1, -1};

//这个点能不能走
bool visit(int x, int y){
    if(x<0 || x>=5 || y<0 | y>=5)
        return false;
    if(matrix[x][y] == 1 || vis[x][y] == 1)
        return false;
    return true;
}

//dfs探路
void dfs(){
    node[head].x = 0;
    node[head].y = 0;
    node[head].pre = -1;
    vis[0][0] = 1;

    while (head < tail){
        nod temp = node[head]; //当前点
        //到达重点,结束
        if(temp.x == 4 && temp.y == 4)
            return;
        //四个方向都探一探,因为是bfs,所以当走远路时,会发现这个点已经被visit过了
        for(int i=0; i<4; i++){
            int newx = temp.x + locx[i];
            int newy = temp.y + locy[i];
            if(visit(newx, newy)){
                node[tail].x = newx;
                node[tail].y = newy;
                node[tail].pre = head;
                tail++;
                vis[newx][newy] = 1;
            }
        }
        head++;
    }
}

void print(int v){
    if(node[v].pre != -1){
        print(node[v].pre);
        cout << "(" << node[v].x << ", " << node[v].y << ")" << endl;
    }
}

int main(){
    for(int i=0; i<5; i++){
        for(int j=0; j<5; j++){
            cin >> matrix[i][j];
        }
    }
    fill(vis[0], vis[0]+30, 0);
    dfs();
    cout << "(0, 0)" << endl;
    print(head);
}

//法二:DFS
struct nod{
    int x, y;
    nod(int xx, int yy):x(xx), y(yy){}
};
int vis[5][5];
int mp[5][5];
int X[4] = {1, -1, 0, 0};
int Y[4] = {0, 0, 1, -1};
int min_dis = inf;
vector<nod>temp, path;

void dfs(int x, int y){
    if(x == 4 && y == 4){
        temp.push_back(nod(x, y));
        vis[x][y] = 1;
        if(temp.size() < min_dis){
            path = temp;
            min_dis = temp.size();
        }
        temp.pop_back();
        vis[x][y] = 0;
        return;
    }
    nod u = nod(x, y);
    temp.push_back(u);
    vis[x][y] = 1;
    for(int i=0; i<4; i++){
        int newx = u.x + X[i];
        int newy = u.y + Y[i];
        if(test(newx, newy))
           dfs(newx, newy);
    }
    temp.pop_back();
    vis[x][y] = 0;
}

树状数

https://www.cnblogs.com/xenny/p/9739600.html

最长上升子序列

https://blog.csdn.net/lxt_Lucia/article/details/81206439

最小生成树

https://www.cnblogs.com/wafish/p/10465426.html
例题:https://www.cnblogs.com/mizersy/p/12256871.html

//kruskal模板
int n, m;
int fa[maxn];
struct Edge {
    int from, to, w;
}edges[maxm]; //maxm应该是点的平方,考虑到每两个点之间都有边存在

bool cmp(Edge a, Edge b){
    return a.w < b.w;
}
int getfa(int x){
    if(fa[x] == x)
        return x;
    else
        return fa[x] = getfa(fa[x]);
}
void Union(int x, int y){
    x = getfa(x);
    y = getfa(y);
    fa[x] = y;
}
int kruskal() {
    int ans = 0;
    for (int i = 0; i < n; ++i) 
    	fa[i] = i;
    sort(edges, edges + m, cmp);
    for (int i = 0; i < m; ++i) {
        Edge e = edges[i];
        int x = find(e.from);
        int y = find(e.to);
        if (x != y) { ans += w; fa[x] = y; }
    }
    return ans;
}

SPFA 判断特殊性质的环,如负权环,边权乘积大于1等

算法思想:我们用数组d记录每个结点的最短路径估计值,用邻接表来存储图G。我们采取的方法是动态逼近法:设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对离开u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且v点不在当前的队列中,就将v点放入队尾。这样不断从队列中取出结点来进行松弛操作,直至队列空为止

https://blog.csdn.net/sxy201658506207/article/details/78779045
https://blog.csdn.net/qq_43475173/article/details/100867312
hdu1217

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
typedef long long ll;

const int nn=20100;
const int mm=30100;
int n,m;
int num=0;
//vis是否在队列中,r进队列次数,v用来标记一个环里的所有点,一个环里的就不用重复spfa
int vis[nn],r[nn],v[nn];
//d距离
double d[nn];

map<string, int>mp;
map<int, int>se;
struct edge{
    int from;
    vector<int>to;
    vector<double>ver;
}e[2*mm];


void init(){
    mp.clear();
    memset(e, 0, sizeof(e));
    memset(v, 0, sizeof(v));
}

//以xx为源点进行spfa
bool spfa(int xx){
    queue<int>q;
    memset(d, 0, sizeof(d));
    memset(vis, 0, sizeof(vis));
    memset(r, 0, sizeof(r)); //更新次数r超过n,即判断含有负权环
    d[xx] = inf;
    vis[xx] = 1;
    v[xx] = 1;
    q.push(xx);
    //队列为空时退出
    while (q.size()){
        int x = q.front();
        q.pop();
        vis[x] = 0; //取出队首元素后,将该元素标记为未在队列中
        int ex = se[x];
        for(int i=0; i<e[ex].to.size(); i++){  //遍历所有邻接点
            int y = e[ex].to[i];
            double z = e[ex].ver[i];
            v[y] = 1; //标记这个点在此子图中
            if(d[y]<d[x]*z){  //如果是判断负权环,则d[i]>d[v]+a[v][i]
                d[y] = d[x]*z;
                r[y] = r[x]+1;
                if(!vis[y]){
                    vis[y] = 1;
                    q.push(y);
                }
            }
            if(r[y] >= n)
                return true;
        }
    }
    return false;
}

int main(){
    int cnt = 0;
    double z;
    char t1[100], t2[100];
    while (scanf("%d", &n) != EOF){
        if(n == 0)
            break;
        cnt++;
        init();
        for(int i=1; i<=n; i++){
            scanf("%s", &t1);
            mp[t1] = i;
        }
        cin >> m;
        for(int i=1; i<=m; i++){
            scanf("%s%lf%s", &t1, &z, &t2);
            int x1=mp[t1], x2=mp[t2];
            int now;
            if(se.find(x1) == se.end()){
                num++;
                now = num;
                se[x1] = now;
            }
            else{
                now = se[x1];
            }
            e[now].from = x1;
            e[now].to.push_back(x2);
            e[now].ver.push_back(z);
        }
        bool flag;
        for(int i=1; i<=n; i++){
            if(!v[i]){
                flag = spfa(i);
                if(flag == true)
                    break;
            }
        }
        if(flag == true)
            cout<<"Case "<<cnt<<": Yes"<<endl;
        else
            cout<<"Case "<<cnt<<": No"<<endl;
    }
}

差分约束

https://blog.csdn.net/consciousman/article/details/53812818
https://blog.csdn.net/ezereal/article/details/52043631
hdu 1384

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
typedef long long ll;

int n;
//vis是否在队列中,d表示距离
int vis[50010], d[50010];

struct edge{
    int to, nex, w;
}e[4*50010];
int headlist[50010], tot;
void add_edge(int u, int v, int w){
    e[tot].to = v;
    e[tot].w = w;
    e[tot].nex = headlist[u];
    headlist[u] = tot++;
}

//以xx为源点进行spfa
void spfa(int xx){
    queue<int>q;
    memset(d, -inf, sizeof(d)); //最长路等于-inf,最短路等于0
    memset(vis, 0, sizeof(vis));
    d[xx] = 0; //最长路等于0,最短路等于inf
    vis[xx] = 1;
    q.push(xx);
    //队列为空时退出
    while (q.size()){
        int x = q.front();
        q.pop();
        vis[x] = 0; //取出队首元素后,将该元素标记为未在队列中
        for(int i=headlist[x]; i!=-1; i=e[i].nex){  //遍历所有邻接点
            int y = e[i].to;
            if(d[y] < d[x] + e[i].w){  //如果是判断负权环,则d[i]>d[v]+a[v][i]
                d[y] = d[x] + e[i].w;
                if(!vis[y]){
                    vis[y] = 1;
                    q.push(y);
                }
            }
        }
    }
}

int main(){
    while(scanf("%d", &n)!=EOF){
        tot = 0;
        memset(headlist, -1, sizeof(headlist));
        int mx = inf, my = 0;
        for(int i=0; i<n; i++){
            int x, y, z;
            scanf("%d%d%d",&x,&y,&z);
            add_edge(x,y+1,z);
            mx = min(mx,x);
            my = max(my,y+1);
        }
        for(int i = mx; i <= my; i++)
        {
            add_edge(i-1,i,0);
            add_edge(i,i-1,-1);
        }
        spfa(mx);
        cout << d[my] << endl;
    }
}

给定两个序列,求另一个

已知后序+中序,求层序遍历结果
PAT1020 Tree Traversals (25 分)

位图bitset

https://www.cnblogs.com/magisk/p/8809922.html

bitset<4> bitset1;  //无参构造,长度为4,默认每一位为0

bitset<8> bitset2(12);  //长度为8,二进制保存,前面用0补充

string s = "100101";
bitset<10> bitset3(s);  //长度为10,前面用0补充

char s2[] = "10101";
bitset<13> bitset4(s2);  //长度为13,前面用0补充

cout << bitset1 << endl;  //0000
cout << bitset2 << endl;  //00001100
cout << bitset3 << endl;  //0000100101
cout << bitset4 << endl;  //0000000010101
bitset<2> bitset1(12);  //12的二进制为1100(长度为4),但bitset1的size=2,只取后面部分,即00

string s = "100101";  
bitset<4> bitset2(s);  //s的size=6,而bitset的size=4,只取前面部分,即1001

char s2[] = "11101";
bitset<4> bitset3(s2);  //与bitset2同理,只取前面部分,即1110

cout << bitset1 << endl;  //00
cout << bitset2 << endl;  //1001
cout << bitset3 << endl;  //1110
bitset<4> foo (string("1001"));
bitset<4> bar (string("0011"));

cout << (foo^=bar) << endl;       // 1010 (foo对bar按位异或后赋值给foo)
cout << (foo&=bar) << endl;       // 0010 (按位与后赋值给foo)
cout << (foo|=bar) << endl;       // 0011 (按位或后赋值给foo)

cout << (foo<<=2) << endl;        // 1100 (左移2位,低位补0,有自身赋值)
cout << (foo>>=1) << endl;        // 0110 (右移1位,高位补0,有自身赋值)

cout << (~bar) << endl;           // 1100 (按位取反)
cout << (bar<<1) << endl;         // 0110 (左移,不赋值)
cout << (bar>>1) << endl;         // 0001 (右移,不赋值)

cout << (foo==bar) << endl;       // false (0110==0011为false)
cout << (foo!=bar) << endl;       // true  (0110!=0011为true)

cout << (foo&bar) << endl;        // 0010 (按位与,不赋值)
cout << (foo|bar) << endl;        // 0111 (按位或,不赋值)
cout << (foo^bar) << endl;        // 0101 (按位异或,不赋值)
bitset<8> foo ("10011011");

string s = foo.to_string();  //将bitset转换成string类型
unsigned long a = foo.to_ulong();  //将bitset转换成unsigned long类型
unsigned long long b = foo.to_ullong();  //将bitset转换成unsigned long long类型

cout << s << endl;  //10011011
cout << a << endl;  //155
cout << b << endl;  //155

拓扑排序

有N个比赛队(1<=N<=500),编号依次为1—N。进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前。现在请你编程序确定排名。

int n,m;
int in[N];//节点入度
int path[N];//存储路径
vector<int> G[N];//G[i]表示i节点所指向的所有其他点
void Topsort()//拓扑排序
{
    priority_queue< int,vector<int>,greater<int> > Q;//最小值先出列
    int cnt=0;//记录可拆解的点数目
    for(int i=1;i<=n;i++)//枚举编号从1到n的点
        if(in[i]==0)//入度为0,入列
            Q.push(i);
 
    while(!Q.empty()) {
        int x=Q.top();//队列首元素
        Q.pop();
 
        path[++cnt]=x;//存储可拆点
        for(int i=0;i<G[x].size();i++){
            int y=G[x][i];
            in[y]--;//入度减一
 
            if(in[y]==0)//入度为0,出列
                Q.push(y);
        }
    }
}

N皇后

#include <bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
#define ull unsigned long long
int pos[21];
int n, sum;
bool checkNQ(int col){
    for(int i=1; i<col; i++){
        if(pos[i]==pos[col] || abs(i-col)==abs(pos[i]-pos[col]))
            return false;
    }
    return true;
}
void dfsNQ(int col){
    if(col == n+1)
        sum++;
    for(int i=1; i<=n; i++){
        pos[col] = i;
        if(checkNQ(col))
            dfsNQ(col+1);
    }
}
int main(){
    cin >> n;
    dfsNQ(1);
    cout << sum << endl;
}

数组复制

char a[] = "sdf";
char b[10];
strcpy(b, a);
//b==>sdf
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值