PAT(甲级)考点


如愿了٩(๑❛ᴗ❛๑)۶2020.3报名,满分了hiahiahia~虽然4个模拟叭

注意事项

  • PAT不允许用gets(),要用fgets(s, maxn, stdin); 读取字符串的长度比真正的长度多1,因此再减去1即可
  • 如果给编号 0   n − 1 0~n-1 0 n1,以±区分男女,注意 − 0 -0 0的处理情况
  • 给字符串可能不合法 如L1-059上半句可能少于3个字母
  • 给的时间可能不按顺序,要看题
  • 给的图可能不连通,要看题目有没有说明
  • 超时可以考虑不用cin,string -> s.c_str();字符串比较:strcmp(a, b) < 0 -> a < b;strcmp(a, b) = 0 -> a = b
  • 有些需要控制格式的可以先把所有结果弄到数组里再控制输出
  • java大数的输入输出格式控制考前要熟悉一遍
    1. File -> new -> Java Project name:Main
    2. src -> new -> package name:Main
    3. Main_package -> new -> Java class -> name: Main 勾选:public static void main(Sting[] args)
    4. import java.util.*
    5. 全部的函数都用static
    6. BigInteger[] a = new BigInteger[1000];
    7. 大数x ,x = x.divide(BigInteger.one);一定要有等于号
    8. boolean
    9. 粘代码之前不要带package一行,但是写代码的时候需要有
    10. 滥用大数运算会T的(1136)……所以 用String,toString()等会更方便,参考1136的提交记录
  • 模拟题要仔细读题
  • 一些小点可能是0的问题 / 输出问题(逻辑控制 / 格式控制)天梯赛L1-009
  • 最短路的优先队列是大根堆,一定要重载反着的比较函数
  • 复习树上倍增LCA,1151
  • n < = 1 0 5 n<=10^{5} n<=105,可以考虑排序进行有序化
  • 一定要注意 l o n g l o n g long long longlong的问题, 1 e 5 1e5 1e5的情况下 i ∗ i i*i ii会超过 l o n g l o n g long long longlong 1104
  • The result must be rounded to the nearest integer that is no greater than the maximum length.这个不是四舍五入,是向下取整(no greater than)
  • 复习一遍任意符号分割
  • 需要注意数位个数,前面可能需要补0
  • 有些模拟题里的分数,需要注意0分和-1(没有值)的区别
  • debug可以找找所有可能的情况(等价类)
  • 任何数不能被0整除
  • 1125 如果ans.size() == 0 直接return不要最后再输出一个’\n’,否则格式错误
  • 有些题目要模,如果有错可以再读一遍题,看清输入输出等
  • BST二叉搜索树要注意题目中是左子树<=根 or 右子树<=根
  • 1108 输出单词的复数形式还是单数形式(读题),且字符串表示的浮点数可能有多个小数点,所以一开始小数点pos初始化应设为n
  • round down to the nearest integer 向下取整
  • 关于树的问题,注意检查节点数n=1、2(两种:左子/右子)的情况 例:1110
  • 如果给百分数,看清给的r是否带%,即给的是r 还是已经除过100的 r%
  • 字符串到数字的映射统一从1开始
  • 前导零处理 (参考1038) 注意全都是0的情况,只有一个0就不是前导零:CF记录:76967384
  • 可能会爆long long(如进制转换、给的是比较大的数字),注意计算范围
  • c++字符串大数加法:
int res[maxn];
string stringadd(string a, string b) {
    int la = a.size(), lb = b.size();
    reverse(a.begin(), a.end());
    reverse(b.begin(), b.end());
    if(la < lb) {
        for(int i = 0; i < lb - la; i++) a += "0";
    } else {
        for(int i = 0; i < la - lb; i++) b += "0";
    }
    int ma = max(la, lb);
    for(int i = 0; i < ma + 5; i++) {
        if(i >= ma) {
            res[i] = 0;
            continue;
        }
        res[i] = 0;
        int now = a[i] - '0' + b[i] - '0';
        res[i] = now;
    }
    for(int i = 0; i < ma; i++) {
        int c = res[i] / 10;
        res[i] = res[i] % 10;
        res[i + 1] += c;
    }
    if(res[ma] != 0) ma++;
    string ret = "";
    for(int i = ma - 1; i >= 0; i--) {
        ret += res[i] + '0';
    }
    return ret;
}
  • 超时可以关同步统一用cin i o s : : s y n c w i t h s t d i o ( f a l s e ) ; ios::sync_with_stdio(false); ios::syncwithstdio(false);
  • 段错误一般都是开小了 / 爆栈了,注意有些是查询的大小不是所有的大小 1039;pat手动加栈不好使:#pragma comment(linker,"/STACK:1024000000,1024000000"),所以遇到dfs数据大的情况改成bfs 1091
  • 类似1022这种归类的题目都用map将下标和名称对应起来,下标从1开始,不要用0,由此可以区分“不存在”这种情况
  • cin 和 getline(cin, str)之间要用cin.get() <==> getchar()
  • 负数不能直接求gcd,先换成绝对值再求

暴力思维

  • 结构体应用 1006 1012 1025 1028 1036 1055 1062 1075(细节题,多次提交满分计数会出错) 1083 1084 1141 1137(四舍五入) 1109(注意题目说的是先从后排开始排,因此如果所有人身高都一样,不能先划分好每排的人再确定位置,因为要求名字小的先排(名字小的在后排)) 1080(排序以后id和下标会变化,因此要注意存一个mp对应,看一次最后提交)
  • 括号匹配一定用栈,只有一种括号才用计数器;配对的这种:如果消除掉中间的一对可以减小问题规模,就可以用栈实现
  • 模拟,注意边界如0等 1001 1005 1008 1011 1035 1041 1042 1046 1047 1048 1050 1054 1056 1060(将一个数转化为科学计数法,注意0的情况) 1061(读题要死) 1063(求交集和并集) 1069 1082(将数字转化为拼音) 1092 1120 1116 1124 1128(虽然数据范围很大,但是并不卡 O ( t ∗ n 2 ) O(t*n^{2}) O(tn2) ) 1132(注意除零错误) 1140 1125 1108(注意如果只有一个合法数组要输出number而不是numbers) 1105(找规律,先变位置再填数) 1149 1153(日期到数字的映射要从1开始才能表示不存在的日期) 1039 1022
  • 多项式加法、乘法 1002 1009
  • for控制图案 1031
  • 进制转换 1010(二分找进制) 1019(判回文)1027 1100(理解题意,只有两位,并且当结果是13、26等13的倍数时,只输出高位不输出低位的tret)
    • :10进制 -> r进制:短除法,一直不停的除,余数对应的字符(如16进制可能有字母)的逆序输出;r进制 -> 10进制:每一位系数乘 r i r^{i} ri 的和
    • 注意结果为0的时候
    • 进制必须比所有字符都大(1010要判断)
    • 可能转换成10进制以后的结果会爆long long 注意考虑判断(1010)
stack<int> st;
char digit[] = {'0', '1', ……};
while(n > 0) {
	st.push(digit[n % base]);
	n /= base;
}
//main
while(!st.empty()) {
	printf("%c", st.top());
	st.pop();
}
  • 二分 1044 1085 1117(给出N天 要求出一个最大的E天,每天骑行的距离都大于E)
  • 高精度 1023(大数加法模拟) 1058(不同进制) 1065(判断溢出即可,但是若要求出是几,就用java大数叭) 1136*第十次加法成功也算失败,因为第一次判n是不是回文数也算一次迭代,先判断,再求和(注意1也要输出为00001,因此可以用string作为输入,输出按照string就可以保留0,构造大数时以string作为参数)
  • 排序 1089(判断采用什么排序方法) 1098(同1089)
    • 插入排序:前面升序,后面两序列一样
    • 归并排序 1029(找中位数)
    • 快速排序 1101
  • 尺取法/二分 1085(先排序,有序化会更好考虑)
  • 思维:1104(求一个数列所有子段的和:统计每个数出现的次数) 1113 1144 1049(规律:计算每一位对应的1的个数,然后相加,每一位的1的计算情况分三种情况)
  • 时间处理:1026 1014 1017 1016

dp

  • 最大子段和 1007
  • 硬币问题(类似01背包) 1068
  • 1045:dp[i] = 以a[i]结尾的(包括a[i])最长值,设a[i]是第x个喜欢的数,则a[i]可以接到 a[1, i - 1] 里,喜欢的数为[1, x]的所有位置后面。

贪心

  • 1037
  • 1033 注意贪心策略
  • 可分割背包 1070
  • 区间dp(伪) 1125区间有相邻要求考虑区间dp,否则考虑哈夫曼树
    • 因为区间dp要求是相邻的区间,但是该题没有相邻的要求,所以该题形式化后为:求一组 a , b , c , … n a,b, c,…n a,b,c,n 使得 a 2 n − 1 \frac{a}{2^{n-1}} 2n1a + b 2 n − 1 \frac{b}{2^{n-1}} 2n1b + c 2 n − 2 \frac{c}{2^{n-2}} 2n2c + d 2 n − 3 \frac{d}{2^{n-3}} 2n3d + …… + n 2 \frac{n}{2} 2n 最大,两边乘 2 n − 1 2^{n-1} 2n1得: a + b + 2 ∗ c + 4 ∗ d + … + 2 n − 2 ∗ n a + b + 2*c + 4 * d+…+2^{n - 2}*n a+b+2c+4d++2n2n最大,即最大的往后面放(×)因为不一定是把一个新的往一个集合里加,而是可能构造好的一组和构造好的另一组放在一起最优,所以上述方法错误
    • 哈夫曼树即可(√):

因为所有长度都要串在一起,每次都等于(旧的绳子长度+新的绳子长度)/2,所以越是早加入绳子长度中的段,越要对折的次数多,所以既然希望绳子长度是最长的,就必须让长的段对折次数尽可能的短。注意k-哈夫曼树:每一次合并会减少K - 1堆,所以只要n - 1是k - 1的倍数就可以了,用0补齐

搜索

  • 隐式搜索bfs + 判回文 1024(注意用字符串存,可能爆long long)
  • 1053 给一棵树,求所有根到叶子的路径,使其路径和为给定值s(dfs,剪枝?剪了一点点)
  • 1091 三维连通块大小(注意条件:mp[i][j][k] == 1 && !vis[i][j][k]),注意层、长、宽的对应 不能dfs因为1e7的数量爆栈也会段错误,改成bfs
  • 1103 因子分解

字符串

  • 马拉车求最长回文子串 1040
  • 找最长公共后缀 1077(暴力即可 / 可以尝试逆序字典树)
  • 类似统计对数的方法 1093(求有几个特定的子序列,要模)
  • 按非数字字母分割字符串 1071
  • 排列字符串使得字典序(数字)最小(重载cmp) 1038
  • 处理前导零:
//1038
int lead = 1;
int flag = 0;
for(int i = 0; i < s.size(); i++) {
    if(lead) {
        int len = s[i].size();
        string now = "";
        for(int j = 0; j < len; j++) {
            if(s[i][j] != '0') {
                lead = 0;
                now = s[i].substr(j, len - j);
                flag = 1;
                break;
            }
        }
        cout << now;
    } else {
        cout << s[i];
        flag = 1;
    }
}
if(!flag) printf("0");
puts("");

数论

  • 筛素数,颠倒顺序 1015
  • 根号判素数 1152 (注意0 和 1)
  • 质因子分解(唯一分解定理) 1059
void decompose(ll x){//唯一分解定理 
	for(ll i = 2; i * i <= x; i++){
		if(x % i == 0){
			fa[k].factor = i;
			while(x % i == 0){
				x /= i;
				fa[k].Count++;
			}
			k++;
		}
	}
	if(x > 1){
		fa[k].factor = x;
		fa[k].Count = 1;
		k++;
	}
}
  • gcd 1088(分数加减乘除,注意看题,细节处理) 1081(分数相加:注意负数问题,还有全是0的情况)
  • 因数分解 1096(模拟) 注意素数的情况(即只有一个不为1的因子:n本身)

数据结构

哈希

  • 构造哈希表,二次探测 1078(注意题意,如果n不是素数才找大于他的素数,且不考虑往前返) 1145(注意查找的时候,对于没有的数:①若探测到hash[pos] == -1(pos存在),则就是没有;②step都探测完了(所有pos上都有数)也没有)
    • 二次探测:若当前key与原来key产生相同的哈希地址,则当前key存在该地址后偏移量为[1,2,3…size - 1]的二次方地址处:
      注意 是(key + step * step) % size 而不是(key % size + step * step)
    • 只带正增量:step∈[1, msz) (msz是哈希表的表长)
for(int i = 0; i < n; i++) {
    int val; scanf("%d", &val);
    int res;
    int flag = 0;
    for(int j = 0; j < msz; j++) {
        res = (val + j * j) % msz;
        if(hashar[res] == -1) {
            hashar[res] = val;
            flag = 1;
            break;
        }
    }
    if(!flag) printf("%d cannot be inserted.\n", val);
}

链表

  • 模拟链表 1032 1052(给出的节点不一定都在链表上,需要遍历一遍求出链表上的值、注意空表) 1074 1133 1097

  • 计算中缀表达式:可以在表达式前后加一个’$’,就会容易操作:操作符栈op和操作数栈num,扫描到一个数,就入num;一个符,与op栈顶比较,若op栈顶优先级高,则出栈计算;否则该符入栈;当‘)’遇到‘(’时,中间的都已经计算完了,因此直接op.pop()弹出左括号,扫描位置++脱去右括号
    在这里插入图片描述
  • 逆波兰表达式RPN:不用括号就能表示优先级
    • 只有一个操作数栈num,每遇到操作数就入栈
    • 遇到一个操作符op,随即执行运算并将结果压回占栈内
    • 转换算法:先将所有的运算都加入括号以明确所有的运算优先级,然后将每一个操作符移到它被界定的那对括号的右括号的后面:所有操作数在RPN的相对次序=在中缀表达式中的次序
      在这里插入图片描述
  • 给一个入栈序列,判断某序列是否为出栈序列 1051
    • 栈混洗:两个对顶栈A、B,借助一个中间栈S将A中的元素全部转移到B中,只允许两种操作:将A的顶元素压入S、将S的顶元素压入B

    • 栈混洗的个数为卡特兰数: ( 2 n ) ! ( n + 1 ) ! n ! \frac{(2n)!}{(n+1)!n!} (n+1)!n!(2n)!

    • 若把 ′ ( ′ '(' ( 看做S的一次入栈, ′ ) ′ ')' ) 看做S的一次出栈,栈混洗 一 一对应一种相同长度的合法括号序列

    • 栈混洗的甄别:任意三个元素的甄别与其他元素无关,对于任意三个整数入栈次序为: i < j < k i<j< k i<j<k,若栈混洗是 … k , … , i … , j … …k, …,i…,j… k,,ij,则一定不是(充要条件:312模式):因此可以

      • 对于一对 i < j i< j i<j,检查结果中没有 j + 1 , i , j j + 1, i , j j+1,i,j 即可 O ( n 2 ) O(n^{2}) O(n2)
      • 或者模拟栈混洗,贪心:对顶栈A(原始入栈序列)、B(结果序列),中间栈S,i指B,j指A,i = j = 1;若栈里有元素且B[i] == st.top(),i++,st.pop();否则就贪心的从A里面一直放元素到S中,直到 j > n || 栈容量不足 -> 不合法;栈顶等于b[i] -> 合法
int a[maxn], b[maxn];
stack<int> st;
int main() {
    int cap, n, k;
    scanf("%d%d%d", &cap, &n, &k);
    for(int i = 1; i <= n; i++) a[i] = i;
    for(int t = 0; t < k; t++) {
        while(!st.empty()) st.pop();
        for(int i = 1; i <= n; i++) scanf("%d", &b[i]);
        int i = 1, j = 1;
        int ok = 1;
        while(i <= n) {
            if(!st.empty() && b[i] == st.top()) {
                i++;
                st.pop();
            } else {
                int flag = 0;
                while(j <= n && st.size() < cap) {
                    st.push(a[j++]);
                    flag = 1;
                    if(st.top() == b[i]) break;
                }
                if(flag == 0) {
                    ok = 0;
                    break;
                }
            }
        }
        if(ok) puts("YES");
        else puts("NO");
    }
	return 0;
}

并查集

  • 1114(求多个家族的财产) 1118 1107 1034(维护集合的点的个数和边权和)

差分数组

  • 区间修改,单点查询 :差分数组(+树状数组) 1095(时间映射->最多1e5)

树和森林(树是为了综合链表和数组的优点,查找、插入均快速)

  • 边数为顶点数 - 1 n n n m m m是同阶的)
  • 给二叉树的前序和中序,求后序遍历……类似
    • 1020
    • 1102(颠倒的中序:右根左)
    • 1138(n很大,不要存)
    • 1043(复习代码,注意镜像的时候,中序的右半边和前序的左半边对应,xx的值要求对)
    • 1086(按照非递归方式给二叉树的中序遍历,求后序遍历:变相的给了先序:push的数字序列;和中序:pop的数字序列,即先序+中序确定一棵树,再算出后序)
    • 1127(之字形bfs:两个栈)
    • 1130(表达式二叉树求中序遍历,对于一个节点x: ‘(’ -> x.lf -> x -> x.rt -> ‘)’;找谁是根:没有父亲的编号即为根。该种读入形式可以参考该题代码)
    • 1119 (给先序、后序遍历,确定树是否唯一,输出随意一个中序遍历)
  • 判断是否为红黑树 1135(可能不是BBST,因此要判断能否建树成功;注意题目中的黑深度是:每个节点的左右子树中黑色节点的个数相同)
    • 红黑树:

    • 一种BBST -> 中序遍历是排好序的

    • 任何动态操作使树的拓扑结构变化(即旋转)都不超过 O ( 1 ) O(1) O(1)

    • *持久性结构:能支持查看历史版本 或 对历史版本做修改 -> 利用相邻版本的关联性:和上一版本相比,有相同的子树就直接指过去,没有就新建
      在这里插入图片描述

    • 结构:引入真二叉树:增加外部节点NULL(第4条:不计外部节点,计根)
      在这里插入图片描述

      • 提升变换(使红点与父亲等高)后,所有底层节点都变为平齐的高度
  • 用结构体表示的树状关系(家谱、供应链……),dfs + bfs 1004 1094 1090 1106 1079
  • 无根树找最深的根 + 判森林 1021
  • 判断是否为完全二叉树 1110(bfs中用两个bool记录有没有中间有空余的形式,注意数每层的个数是不能确定的有无空余的情况 两个反例见提交记录)
  • 给一个序列,求唯一的完全二叉搜索树的bfs 1064 1099(给树的形状,建立二叉搜索树)
    • 完全二叉搜索树要求左子树小于根,右子树大于等于根(看题),除最后一层外,每一层都必须铺满,最后一层要从左到右铺,中间不能有空缺;搜索树的中序遍历是一个有序数组 解法:二叉树的中序遍历建树即为输出
      在这里插入图片描述
      因为完全二叉树的层次遍历标号如上;而使用左儿子为 x ∗ 2 x*2 x2,右儿子为 x ∗ 2 + 1 x*2+1 x2+1的编号方法也如上,因此直接中序方法建树即可
  • 像空二叉搜索树中依次插入(从根开始左右下放)节点,求树的遍历 1115(默认根是输入第一个数,注意是左子树<=根)
  • 模拟实现AVL树左旋右旋(zig、zag)操作 1066:
    • 插入操作:按树左右下放即可

    • 删除操作:

      • 被删除的点若只有一个孩子,则用他的孩子替换他即可
      • 若有两个孩子,要找到根节点的直接后继(中序遍历的下一个数) x x x x x x只可能有右孩子,不会有做孩子,因为是中序的下一个,如果有左孩子则还会往下,直接后继就不会是 x x x),用 x x x替换他,然后将原来 x x x的右孩子替换他即可
        在这里插入图片描述
    • 对于新插入的点,对于他的第一个不平衡的祖先(沿着到根的路径),进行操作后,所有祖先都会平衡;也可能没有祖先失衡,整个树还是平衡的:从被插入节点的祖父开始

    • 对于新删除的点,其更高的祖先仍可能失衡,需要 O ( l o g n ) O(logn) O(logn)次调整:从被删除节点的父亲开始

    • zig(v)(v右旋):v的左子节点c变为根,v变为c的右子节点,c原来的右子节点变为v的左子节点

    • zag(v)(v左旋):v的右子节点c变为根,v变为c的左子节点,c原来的左子节点变为v的右子节点
      在这里插入图片描述

    • zagzag(g) 连续三代全都向右;zigzig(g) 连续三代全都向左
      在这里插入图片描述

    • zigzag:之字形(图为zigzag),先zig§,再zag(g)
      在这里插入图片描述

  • 用set<结构体>模拟 1129(求当前出现次数最多的k个数)

  • 对顶堆+栈:求动态中位数 1057

  • 给一个完全二叉树,判断是否为堆/大根堆/小根堆 1155

  • 构造(判断)完全二叉堆 1147(完全二叉树的层次遍历<=>秩)

  • 堆:逻辑上是完全二叉树;物理上是一个数组:1为根,x2为左孩子, x2+1为右孩子

    • 完全二叉树:逻辑节点与物理元素在数组中的秩以层次遍历序列相对应
    • 注意与二叉搜索树的区别:二叉搜索树不一定是完全树,且左儿子、右儿子、根均有关系
    • 任何一个点的值都<=他父亲: x / 2 x/2 x/2(大根堆)
    • 获取最值:堆顶(tree[1])
    • 插入:插入在数组的最后<==>在完全二叉树的末尾拓展一个节点,然后上滤进行合法性的调整
      • 上滤:原因:新插入的节点值>父亲,一直调整到合法(可能成为堆顶)
    • 删除(最大元):删除堆顶,以数组最后一个元素代替,下滤进行合法性的调整
      • 下滤:当前节点的值 < 至少一个孩子,则与左右孩子中更大的进行交换(保证互换后当前节点一定>=两个孩子)
    • 批量建堆:
      • 若依次插入每一个, O ( n l o g n ) O(nlogn) O(nlogn)
      • 对于一个初始数组,自下而上,自右而左的,从第 ⌊ n / 2 ⌋ \left \lfloor n/2\right \rfloor n/2个节点(秩从1开始计数)开始,对每一个节点下滤,直到1号即根节点也下滤完成
    • 用完全二叉堆优化选择排序
      • 堆排序(就地算法):
        1. 将待排序区间建堆(批量建堆 O ( n ) O(n) O(n)
        2. 反复交换堆顶和待排序的位置的元素(即将堆顶放在该数组的尾部),更新堆的区间长度,下滤当前的堆顶
          在这里插入图片描述
  • 二叉搜索树上的LCA 1143 1151(二叉树的LCA ==注意该题的写法:用一个新的局部变量x表示当前idx,不要用全局变量tot == 给一棵树如果说保证惟一的,说明没有相同值)

    • 将两个点向上的链找到,第一个相同的即为LCA -> 超时
    • 树上倍增 / (RMQ查询)
    • 注意根的下标是1,根的父亲下标为0,否则会访问下标数组为-1的元素,造成段错误
int in[maxn], pre[maxn];
struct node {
    int val, l, r, f;
} tree[maxn];
int tot;
map<int, int> idx;
int build(int prel, int prer, int inl, int inr, int fa) {
    tree[++tot].val = pre[prel];
    int x = tot;//注意这里不要用全局变量
    tree[x].f = fa;
    idx[pre[prel]] = x;
    int pos = -1;
    for(int i = inl; i <= inr; i++) {
        if(in[i] == pre[prel]) {
            pos = i;
            break;
        }
    }
    if(inl <= pos - 1) {
        int xx = pos  - inl + prel;
        tree[x].l = build(prel + 1, xx, inl, pos - 1, x);
    } else tree[x].l = -1;
    if(pos + 1 <= inr) {
        int xx = pos  - inl + prel + 1;
        tree[x].r = build(xx, prer, pos + 1, inr, x);
    } else tree[x].r = -1;
    return x;
}

  • 暴力找符合条件的环(的个数) 1139(离散化)
顶点覆盖
  • 判断顶点覆盖(一组点覆盖了所有的边):1134
图的遍历
  • 询问某节点的L层内的点有几个 1076(包含这样概念的一定用bfs,因此dfs会有回向边,即可能某一点有短的路,但是dfs时走了长的,vis后就不会再访问了,造成错误) bfs注意先使vis=1再入队
最短路
  • 单源最短路 1030(两种边权)
  • 最短路计数 1003 c n t [ v ] + = c n t [ u ] cnt[v] += cnt[u] cnt[v]+=cnt[u] 最短路维护点权、边权
  • dij + dfs 1018
  • 1087(最短路,最短路计数、若有多条取点权和最大的,若仍有多条求途径的点的平均权值最大的(平均点权值最大是满足最优子结构的,因此可以不用dfs:如果点权和一样大,那么就选择路径上结点个数少的路径),输出路径)
  • 有环有向图的最短路,并输出路径 1131(处理转站的情况)
最大团
  • 暴力枚举判定最大团、团 1142(暴力)
连通性(并查集)
  • 求连通块个数 1013
图着色
  • 判断是否为合法的图着色序列 1154(离散化, 图可能不连通)
拓扑排序
  • 给一个有向图,判断所给序列是否为拓扑排序 1146 只需要依次判断当前点的入度是否为0即可
欧拉路、哈密顿路与TSP
  • 判断TSP 1150(TSP环首先要判断路上的个数是否为n,再判首尾是否相同)
  • 每条边经过一次的路径是欧拉路,每个点只经过一次是哈密顿路
  • 判断哈密顿回路 1122
  • 判断欧拉路、欧拉回路 1126
    • 首先图必须是联通的,用并查集判即可
    • 无向图欧拉回路:所有点度数都为偶数
    • 无向图欧拉路径:两个点(或0个点)度数为奇数,其余点(或所有点)度数为偶数
    • 有向图欧拉回路:所有点入度=出度
    • 有向图欧拉路径:一个点入度=出度+1,一个点出度=入度+1,其余点(或所有点)入度=出度
  • 查找该路径:
//已知存在欧拉路径,找该路径
void dfs(int u){//s1~sn中存储的是欧拉路径上的点序列
    for(int v=1;v<=n;v++){
        if(mp[u][v]>0){
            mp[u][v]--;
            mp[v][u]--;
            dfs(v);
        }
    }
    s[temp--]=u;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值