解题记录A

11.13

cin.getline(s,sizeof s,’\n’);

11.15 树

  • 小球-drop
    • 大事化小,n层化n-1层,计算进入该结点的次数
  • 二叉树遍历-flist
    • 中序+层序==前序
    • 递归+按层遍历=前序遍历
    • rank表,寻找最小结点
    • 子树上结点号最小的结点是子树的根结点
  • FBI树
    • 同时进行递归计算FBI和后序遍历
  • 猜数字
    cout<<(min+max)/2<<endl;
    
  • 人以群分
    • 单调序列
  • 最小环
    • gcd多个最小环
    • 物以类聚(如1、3、5、6、4、2)

11.17 树+堆

超级对拍程序

rem Name: Batch For Check
rem Copyright: All Right Reserved
rem Author: Chen Jie
rem Date: 2020/10/17
rem Description: RENAME the *.bat file and run it.
rem The batch will consider succesive spaces as one.
@echo off
::no parameter then begin for loop
if "%1"=="" goto loop
set BAT_NAME=%~nx0
::BAT_NAME=TFILE_NAME.bat
set FILE_NAME=%BAT_NAME:~0,-4%
::if no exist the corresponding input file, then end the batch
if not exist %FILE_NAME%%1.in (
	goto end
)
if exist %FILE_NAME%%1.out (
	set ANS_NAME=%FILE_NAME%%1.out
)
if exist %FILE_NAME%%1.ans (
	set ANS_NAME=%FILE_NAME%%1.ans
)
copy %FILE_NAME%%1.in %FILE_NAME%.in >nul
echo Problem Test Data %1
time<enter
%FILE_NAME% < %FILE_NAME%.in > %FILE_NAME%.out
time<enter
::if exist error, then pause for showing the difference
fc %FILE_NAME%.out %ANS_NAME% /w /n
if errorlevel 1 (
	pause>nul
)
del %FILE_NAME%.in
del %FILE_NAME%.out
::end the batch
goto end
:loop
::call the corresponding data batch
for %%i in (0 1 2 3 4 5 6 7 8 9 10 11) do call %0 %%i
echo Press Any Key To Exit ...
pause>nul
:end
就地建堆函数
  • make_heap(),pop_heap(),push_heap()
    C++中的make_heap(), pop_heap()的头文件为<algorithm>。作用与priority_queue<>;中的成员函数相同,可以单独使用。
    
    make_heap(begin,end,greater<int>());
    
    在容器范围内,就地建堆,保证最大值在所给范围的最前面,其他值的位置不确定
    pop_heap(begin,end,greater<int>());
    
    将堆顶(所给范围的最前面)元素移动到所给范围的最后,并且将新的最大值置于所给范围的最前面
    push_heap(begin,end,greater<int>());
    
    当已建堆的容器范围内有新的元素插入末尾后,应当调用push_heap将该元素插入堆中。
code到word带格式复制
  • 二叉树输出(btout)
    • 一个数组能解决的事不要用结构体
  • 查找二叉树(tree_a)
  • 对称二叉树(tree_c)
  • 合并果子(fruit)

11.18 堆+图

最小字典序Euler回路(逆序)

  • 骑马修栅栏(fence)
    void find(int now)
    {
        for (int k = mi; k <= ma; k++)
            if (available[now][k] > 0)
            {
                available[now][k]--;
                available[k][now]--;
                find(k);
            }
        c[++cnt] = now;
    }
    
命令参数
  • VS2019-项目-属性-调试-命令参数

    • 命令行格式指定输入文件
      < $(ProjectDir)$(Configuration)\$(ProjectName).in
      
  • 基于红黑树的可重复集合

    multiset<int>st;
    st.insert(a);
    cout << *st.begin() << ' ';
    st.erase(st.begin());
    cout << *(--st.end()) << endl;
    st.erase(--st.end());
    
  • 看病-hp

    • release比debug快,约4~6~9
    • 简单的程序倍数高
      0.11-0.96
      0.7-4
      1.4-5.77
      
  • 小明的账单-bill

    • heap不会错
    • multiset太慢
  • 铲雪车(snow)

    • 加起来就好了,别多想
  • 珍珠(bead)

    • 不允许指向引用的指针、迭代器,即不允许定义
      vector<typename&>vec;
      

11.19 第三节 最短路径算法

F l o y e d Θ ( N 3 ) Floyed \Theta(N^3) FloyedΘ(N3)

  • 适用于出现负边权的情况
    初始化:点u、v如果有边相连,则dis[u][v]=w[u][v]。
    如果不相连则dis[u][v]=INT_MAX
    
    for (k = 1; k <= n; k++)
        for (i = 1; i <= n; i++)
            for (j = 1; j <= n; j++)
                if (dis[i][j] > dis[i][k] + dis[k][j])
                    dis[i][j] = dis[i][k] + dis[k][j];
    
  • 牛的旅行-travel
    这两个牧场都在John的农场上。John将会在两个牧场中各选一个牧区,然后用一条路径连起来,使得连通后这个新的更大的牧场有最小的直径。注意,如果两条路径中途相交,我们不认为它们是连通的。只有两条路径在同一个牧区相交,我们才认为它们是连通的。
    现在请你编程找出一条连接两个不同牧场的路径,使得连上这条路径后,这个更大的新牧场有最小的直径。
    
    用Floyed求出任两点间的最短路,然后求出每个点到所有可达的点的最大距离,记做mdis[i]。(Floyed算法) 
    r1=max(mdis[i]);
    然后枚举不连通的两点i,j,把他们连通,则新的直径是mdis[i]+mdis[j]+(i,j)间的距离。 
    r2=min(mdis[i]+mdis[j]+dis[i,j]);
    re=max(r1,r2);//旧最大与新直径的最小的最大
    re就是所求。
    

D i j k s t r a Θ ( N 2 ) Dijkstra \Theta(N^2) DijkstraΘ(N2)

  • 不能处理存在负边权的情况
    设起点为s,dis[v]表示从s到v的最短路径,pre[v]为v的前驱节点,用来输出路径。
    a)初始化:dis[v]=(v≠s); dis[s]=0; pre[s]=0; 
    b)For (i = 1; i <= n ; i++)
        1.在没有被访问过的点中找一个顶点u使得dis[u]是最小的。
        2.u标记为已确定最短路径
        3.For与u相连的每个未确定最短路径的顶点v
            if (dis[u] + w[u][v] < dis[v]) 
            {
                dis[v] = dis[u] + w[u][v];
                pre[v] = u;
            }
    c)算法结束:dis[v]为s到v的最短距离;pre[v]为v的前驱节点,用来输出路径。
    
    for (int i = 1; i <= n; ++i)
    {
        int k = 0;
        for (int j = 1; j <= n; ++j)
            if (!ok[j] && ans[j] < ans[k])
                k = j;
        if (!k)break;
        ok[k] = true;
        for (int j = 1; j <= n; ++j)
            if (!ok[j] && ratio[j][k])
                ans[j] = std::min(ans[j], ans[k] * ratio[j][k]);
    }
    

B e l l m a n − F o r d Θ ( N E ) Bellman-Ford \Theta(NE) BellmanFordΘ(NE)

  • 能够处理存在负边权的情况,但无法处理存在负权回路的情况
    设s为起点,dis[v]即为s到v的最短距离,pre[v]为v前驱。w[j]是边j的长度,且j连接u、v。
    初始化:dis[s]=0, dis[v]=∞(v≠s),pre[s]=0
    For (i = 1; i <= n-1; i++)
        For (j = 1; j <= E; j++)//注意要枚举所有边,不能枚举点。
            if (dis[u] + w[j] < dis[v])//u、v分别是这条边连接的两个点。
            {
                dis[v] = dis[u] + w[j];
                pre[v] = u;
            }
    
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
        {
            dis[f[j].y] = std::min(dis[f[j].y], dis[f[j].x] + f[j].w);
            dis[f[j].x] = std::min(dis[f[j].x], dis[f[j].y] + f[j].w);
        }
    

S P F A Θ ( k E ) SPFA \Theta(kE) SPFAΘ(kE)

  • B e l l m a n − F o r d Bellman-Ford BellmanFord算法的队列实现
  • k k k的平均值是2
    dis[i]记录从起点s到i的最短路径,w[i][j]记录连接i,j的边的长度。pre[v]记录前趋。
    team[1..n]为队列,头指针head,尾指针tail。
    布尔数组exist[1..n]记录一个点是否现在存在在队列中。
    初始化:dis[s]=0,dis[v]=∞(v≠s),memset(exist,false,sizeof(exist));
    起点入队team[1]=s; head=0; tail=1;exist[s]=true;
    do
    {
    1、头指针向下移一位,取出指向的点u。
    2、exist[u]=false;已被取出了队列
    3、For与u相连的所有点v//注意不要去枚举所有点,用数组模拟邻接表存储
        if (dis[v]>dis[u]+w[u][v])
        {
            dis[v]=dis[u]+w[u][v];
            pre[v]=u;
            if (!exist[v])//队列中不存在v点,v入队。
            {
                //尾指针下移一位,v入队;
                exist[v]=true;
            }
        }
    }
    while (head < tail);
    
    dis[i] = 0;
    team[0] = i;
    int head = 0, tail = 1;
    exist[i] = true;
    do
    {
        int u = team[head];
        if (++head == 2 * 牧场)head = 0;
        exist[u] = false;
        for (int j = 1; j <= num[u]; ++j)
        {
            int v = a[u][j];
            if (dis[v] > dis[u] + w[u][v])
            {
                dis[v] = dis[u] + w[u][v];
                if (!exist[v])
                {
                    team[tail] = v;
                    if (++tail == 2 * 牧场)tail = 0;
                    exist[v] = true;
                }
            }
        }
    } while (head != tail);
    

11.20

int a[5] = { 1,2,3,4,5 };
int* p = a;
&(p + 2);//“&”要求左值
&*(p + 2);//等于a + 2

11.21 第四节 图的连通性问题

一、判断图中的两点是否连通

  • Floyed算法
    • 时间复杂度: Θ ( N 3 ) \Theta(N^3) Θ(N3)
  • 遍历算法
    • 时间复杂度: Θ ( N 2 ) \Theta(N^2) Θ(N2)

二、最小环问题

最小环就是指在一张图中找出一个环,使得这个环上的各条边的权值之和最小。在Floyed的同时,可以顺便算出最小环。
记两点间的最短路为dis[i][j],g[i][j]为边<i,j>的权值。
for (k = 1; k <= n; k++)
{
    for (i = 1; i <= k - 1; i++)
        for (j = i + 1; j <= k - 1; j++)
            answer = min(answer, dis[i][j] + g[j][k] + g[k][i]);
    for (i = 1; i <= n; i++)
        for (j = 1; j <= n; j++)
            dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}
answer即为这张图的最小环。
一个环中的最大结点为k(编号最大),与它相连的两个点为i,j,这个环的最短长度为g[i][k]+g[k][j]+(i到j的路径中,所有结点编号都小于k的最短路径长度)。
根据Floyed的原理,在最外层循环做了k-1次之后,dis[i][j]则代表了i到j的路径中,所有结点编号都小于k的最短路径。
综上所述,该算法一定能找到图中最小环。

三、求有向图的强连通分量

Kosaraju算法可以求出有向图中的强连通分量个数,并且对分属于不同强连通分量的点进行标记。它的算法描述较为简单:
(1) 第一次对图G进行DFS遍历,并在遍历过程中,记录每一个点的退出顺序。
(2)倒转每一条边的方向,构造出一个反图G’。然后按照退出顺序的逆序对反图进行第二次DFS遍历。
每次遍历得到的那些点即属于同一个强连通分量。
QQ截图复制色号
  • 按C复制色号dd,dd,dd,Ctrl+C复制16进制色号#hhhhhh

11.28

  • &*=*&=
    • 取地址运算符与解除引用运算符互逆

12.6

MyClass#1# MyFunc(MyClass#2# x)
{
	cout << "MyFunc" << endl;
	return x;
}

MyClass b = MyFunc(a);
  • #2#不引用:先复制构造x,返回时根据#1#确定析构顺序
    • #1#引用:先析构返回值(若需要),再复制构造b(局部变量无法传递)
    • #1#不引用:先复制构造b,再析构返回值(若需要)
  • 神奇的 Θ ( 1 ) \Theta(1) Θ(1)快速乘
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值