• 【概念理论】不存在的NOIP2016


    时间:2017.6.17

    0x01搜索

    一、定义

    1.从数据集合中找出目标元素进行处理。
    2.当我们难以通过分析解决给定问题,或者找不到一个能有效解决问题的算法时,就不得不依靠反复的试错来寻求问题的答案了。  而且在这里,可以用启发式搜索,即利用问题拥有的启发信息来引导搜索,达到减少搜索范围、降低问题复杂度的目的。

    二、对象

    1.目的: 可以是需要进行处理的目标元素, 或者是答案本身。
    2.类型: 可以是一个数值, 也可以是一个组合, 甚至可能可以是一个集合

    三、数值

    类型: 线性, 二分, 散列 
    1.线性:从数组开头依次访问各元素,检查该元素是否与目标值相等。 线性搜索算法效率很低, 但是适用于任何形式的数据。
    2.二分:通过不断不断缩小解存在的范围, 从而求得问题最优解的方法。 效率较高,应用较广。
    3.散列:根据各元素的值来确定存储位置, 然后将位置保管在散列表中。 散列可以高效的执行动态插入,搜索,删除操作。

    四、组合

    1.穷竭搜索:将所有的可能性罗列出来,在其中寻找答案。
    2.迭代加深:对于可以用回溯求解但解答树的深度没有明显上限的题目。
    3.状态空间搜索:找到一个从初始状态到终止状态的路径。
    4.回溯法:将生成与检查有机的结合起来,实现剪枝。 
    5.A* IDA*:设计一个乐观的估价函数,实现剪枝。

    五、练习题 2017.6.5

    尚未能包含大框架,
    详细见具体知识点。

    0x02数据结构

    一、基础

    抽象数据类型(ADT):表(list,hash), 栈(stack), 队列(queue)
    树相关(Tree):二叉树, 堆(heap)
    库(STL):排序(sort), 集合(set), 映射(map)

    二、中级

    树相关: 二叉搜索树, 线段树, 
    图相关: 并查集, 有向无环图(DAG), 

    0x03图论

    图的基本概念:

    一、图是什么

    1.定义:图由顶点和边构成。顶点代表对象,边代表两个对象之间的连接关系。记为图G=(V(点集),E(边集));
    2.应用:图被应用于解决错综的网状关系的问题当中。 往往可以用之建立相关的模型套入相关算法以解决问题。

    二、图的分类

    1.依据一:边没有指向性的叫做无向图(朋友关系,路线图),边具有指向性的叫做有向图(数值大小,流程图)。
    2.依据二:根据边有无附加的属性(具有权值),将图分为带权图,和不带权图。
    3.依据三:根据图是否有环(从一个顶点出发经过若干边可以回到该顶点)分为有环图和无欢图。
    4.依据四:任意两点之间都有路径的图叫做连通图,没有的叫非连通图。
    5.典型的无向图:没有圈的连通图叫做树,没有圈的非连通图叫做森林。
    6.典型的有向图:没有圈的有向图叫做DAG。

    三、图的表示

    0.背景:图作为与线性不同的另一种新的数据结构类型,为了能够在程序中对之进行处理,需要将之按某种方法存储下来。
    1.邻接矩阵:用一个二维数组表示(int e[maxn][maxn];),e[i][j]表示顶点i与顶点j的距离,若不连通可以将之标记为inf。
    2.邻接表一:用链表存储从顶点0出发有到顶点1,2,3的边(int first[maxn],next[maxn];),其中first[i]表示顶点i出发的第一条边,next[i]表示边i的下一条边(可以用-1表示不存在)。
    3.邻接表二:用向量存储从某顶点出发有到其余顶点的边(vector<int>G[maxn];),其中G[i]存储了顶点i出发能够到达的其余边。

    图的相关算法(本节为大纲,具体参见详细算法整理):

    四、图的搜索

    五、图的最短路

    五、最小生成树

    六、网络流

    图相关的数据结构(本节已全部移至数据结构章节)
    七、树

    二叉树
    最小堆
    最大堆
    并查集
    线段树
    AVL树
    平衡树
    红黑树
    树套树
    主席树
    树状数组
    二叉搜索树

    八、图

    0x04DFS

    一、定义

    深度优先搜索算法(英语:Depth-First-Search,简称DFS)是一种用于遍历或搜索树或图的算法。沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。属于盲目搜索。
    深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多相关的图论问题,如最大路径问题等等。

    二、基本框架(待修改)

    1.访问顶点v
    2.依次从v的未被访问的邻接点出发,对图进行深度优先遍历;直至图中和v有路径相通的顶点都被访问
    3.若此时图中尚有顶点未被访问,则从一个未被访问的顶点出发,重新进行深度优先遍历,直到图中所有顶点均被访问过为止

    三、用处

    1.DFS求通块(因为能够遍历图, )
    2.

    四、本章节相关专题建议阅读顺序

    1.求通块
    2.全排列
    3.回溯法
    4.

    练习题 2017.5.6

    1.Codevs1294 全排列    
    2.Codevs1295 N皇后问题    
    3.Codevs3895 环素数       
    4.Codevs1983 等式问题
    5.Codevs1018 单词接龙
    6.Codevs1026 逃跑的拉尔夫 

    0x05最小生成树

    一、讲道理

    二、Kruscal

    codevs1078

    #include<iostream>
    #include<algorithm>
    #include<vector>
    using namespace std;
    int n, a[110][110], fa[110], co, ans;
    struct side{
        int u, v, w; 
        side (int u, int v, int w):u(u),v(v),w(w){}
        bool operator < (const side b)const{ return w<b.w;}
    };
    vector<side>e;
    int find(int x){ return x==fa[x]? x : fa[x]=find(fa[x]);}
    int main(){
        cin>>n;
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= n; j++){
                int x; cin>>x;
                if(i >= j)continue;
                e.push_back(side(i, j, x));
            }
        }
        sort(e.begin(), e.end());
        for(int i = 1; i <= n; i++)fa[i] = i;
        for(int i = 0; i < e.size(); i++){
            if(find(e[i].u) != find(e[i].v)){
                ans += e[i].w;
                fa[find(e[i].u)] = find(e[i].v);
            }
        }
        cout<<ans;
        return 0;
    }

    Codevs1231

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    
    int fa[100000];
    int find(int x){ return fa[x]==x ? x : fa[x]=find(fa[x]);}
    
    struct L{ long long u, v, w; }e[100000];
    bool operator < (const L A, const L B){ return A.w<B.w;}
    
    int main(){
        int n, m, count = 0;
        long long ans = 0;
        scanf("%d%d", &n, &m);
        for(int i = 0; i < m; i++)
            scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
        sort(e,e+m);
        for(int i = 0; i <= n; i++) fa[i] = i;
        for(int i = 0; i <= m; i++){
            if(find(e[i].u) != find(e[i].v)){
                fa[find(e[i].u)] = e[i].v;
                ans += e[i].w;
                count++;
            }
            if(count == n-1)break;
        }
        printf("%lld
    ", ans);
        return 0;
    }

    三、Prim

    0x06子集生成

    问:生成0~n所有的子集。
    答:

    一、增量构造法

    #include<iostream>
    using namespace std;
    int n, A[20];
    void dfs(int cur){
        for(int i = 1; i < cur; i++)cout<<A[i]<<" ";
        cout<<"
    ";
        int s = A[cur-1]+1;
        for(int i = s; i < n; i++){
            A[cur] = i;
            dfs(cur+1);
        }
    }
    int main(){
        cin>>n;
        A[0] = -1;
        dfs(1);
        return 0;
    }

    二、位向量法

    #include<iostream>
    using namespace std;
    int n, A[10];
    void dfs(int cur){
        if(cur == n){
            for(int i = 0; i < n; i++)
                if(A[i])cout<<i<<" ";
            cout<<"
    ";
        }else{
            //A[cur] = 1;
            dfs(cur+1);
            A[cur] = 1;
            dfs(cur+1);
            A[cur] = 0;
        }
    }
    int main(){
        cin>>n;
        dfs(0);
        return 0;
    }

    三、二进制法

    #include<iostream>
    using namespace std;
    int main(){
        int n;
        cin>>n;
        for(int i = 0; i < (1<<n); i++){
            for(int j = 0; j < n; j++)
                if(i&(1<<j))cout<<j<<" ";
            cout<<"
    ";
        }
        return 0;
    }

    0x07ADT抽象数据类型

    一、定义

    数据数据元素,数据关系以及相关的操作。

    二、内容

    1. C++的Standard Template Library(模板库)
    2. 图论算法的分装

    三、STL

    <algorithm>
    <vector>
    <set>
    <map>
    <stack>
    <queue>
    <deque>
    <list>
    <utility><functional><iterator><array><forward_list><unordered_map><memory><numeric><unordered_set>

    四、

    0x08图的最短路径

    一、例题(为形象理解,可无视):
    废话:
    暑假,小哼准备去一些城市旅游。有些城市之间有公路,有些之间则没有,为了节省经费以及方便计划旅程,小哼希望在出发之前知道任意两个城市之间的最短路径。

    数据://本例所有数据均针对有向无环图(DAG)
    //代码看不懂的同学可以画一画样例数据的图的说。
    4 8
    1 2 2
    1 3 6
    1 4 4
    2 3 3
    3 1 7
    3 4 1
    4 1 5
    4 3 12
    //ans: 0 2 5 4
    
    6 9
    1 2 1
    1 3 12
    2 3 9
    2 4 3
    3 5 5
    4 3 4
    4 5 13
    4 6 15
    5 6 4
    //ans:0 1 8 4 13 17
    
    4 5
    1 4 9
    4 3 8
    1 2 5
    2 4 6
    1 3 7
    //ans:0 5 7 9
    
    5 5
    2 3 2
    1 2 -3
    1 5 5
    4 5 2
    3 4 3
    //ans:0 -3 -1 2 4
    
    5 7
    1 2 2
    1 5 10
    2 3 3
    2 5 7
    3 4 4
    4 5 5
    5 3 6
    //ans:0 2 5 9 9 

    二、Floyd-Wallshall

    讲道理
    

    本题Code

    #include<iostream>
    using namespace std;
    int n, m, e[110][110];
    const int inf = 0xffffff;
    int main(){
        cin>>n>>m;
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                e[i][j] = i==j ? 0 : inf;
        for(int i = 0; i < m; i++){
            int a, b, c;   cin>>a>>b>>c;
            e[a-1][b-1] = c;
        }
        for(int k = 0; k < n; k++)
            for(int i = 0; i < n; i++)
                for(int j = 0; j < n; j++)
                    if(e[i][j] > e[i][k]+e[k][j])
                        e[i][j] = e[i][k]+e[k][j];
        for(int i = 0; i < n; i++)cout<<e[0][i]<<" ";
        return 0;
    }

    三、dijkstra

    讲道理
    

    本题Code

    #include<iostream>
    #include<algorithm>
    using namespace std;
    int n, m, d[110], book[110];
    int e[110][110];
    const int inf = 0xfffff;
    int main(){
        cin>>n>>m;
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                e[i][j] = (i==j ? 0 : inf);
        for(int i = 0; i < m; i++){
            int a, b, c;  cin>>a>>b>>c;
            e[a-1][b-1] = c;
        }
        book[0] = 1;
        for(int i = 0; i < n; i++)d[i] = e[0][i];
        for(int i = 0; i < n; i++){
            int x, y = inf;
            for(int j = 0; j < n; j++)if(!book[j] && d[j]<y)y = d[x=j];
            book[x] = 1;
            for(int j = 0; j < n; j++)d[j] = min(d[j], d[x]+e[x][j]);
        }
        for(int i = 0; i < n; i++)cout<<d[i]<<" ";
        return 0;
    }

    优化的说

    #include<iostream>
    #include<algorithm>
    using namespace std;
    int n, m, d[110], book[110];
    int e[110][110];
    int u[110], v[110], w[110], first[110], next[110]; //优化1:用邻接表代替邻接矩阵
    const int inf = 0xfffff;
    int main(){
        cin>>n>>m;
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                e[i][j] = (i==j ? 0 : inf);
        for(int i = 1; i <= n; i++)first[i] = -1;
        for(int i = 1; i <= m; i++){
            cin>>u[i]>>v[i]>>w[i];
            e[u[i]][v[i]] = w[i]; 
            next[i] = first[u[i]];
            first[u[i]] = i;
        }
        book[0] = 1;
        for(int i = 2; i <= n; i++)d[i] = inf;
        for(int i = 1; i <= n; i++){
            int x, y = inf;
            int k = first[i];
            while(k != -1){
                if(!book[u[k]] && d[u[k]]<y)y = w[x=u[k]];
                k = next[k];
            }
            book[x] = 1;
            for(int j = 1; j <= n; j++){
                int k = first[x], t = inf;
                while(k != -1){
                    if(v[k]==j){ t = w[k]; break;}
                    k = next[k];
                }
                if(d[j]>d[x]+t) d[j] = d[x]+t;
            }
        }
        for(int i = 1; i <= n; i++)cout<<d[i]<<" ";
        return 0;
    }

    优化的说2

    //优化2,3:向量存储+优先队列
    

    四、bellman-ford

    讲道理

    本题Code

    #include<iostream>
    using namespace std;
    int u[110], v[110], w[110], d[110];
    const int inf = 0xfffff;
    int main(){
        int n, m;   cin>>n>>m;
        for(int i = 1; i <= m; i++)cin>>u[i]>>v[i]>>w[i];
        for(int i = 2; i <= n; i++)d[i] = inf;
        for(int k = 0; k < n; k++){
            for(int i = 1; i <= m; i++)if(d[v[i]]>d[u[i]]+w[i])
                d[v[i]] = d[u[i]]+w[i];
        }
        for(int i = 1; i <= n; i++)cout<<d[i]<<" ";
        return 0;
    }

    优化的说

    #include<iostream>
    using namespace std;
    int u[110], v[110], w[110], d[110];
    const int inf = 0xfffff;
    int main(){
        int n, m;   cin>>n>>m;
        for(int i = 1; i <= m; i++)cin>>u[i]>>v[i]>>w[i];
        for(int i = 2; i <= n; i++)d[i] = inf;
        for(int k = 0; k < n; k++){
            int check = 1;  //优化1:本次没有松弛操作,已经得到了最短路
            for(int i = 1; i <= m; i++)if(d[v[i]]>d[u[i]]+w[i])
                { d[v[i]] = d[u[i]]+w[i]; check = 0;}
            if(check)break;
        }
        for(int i = 1; i <= n; i++)cout<<d[i]<<" ";
        int flag = 0;//功能1:检测负权回路
        for(int i = 1; i <= m; i++)if(d[v[i]]>d[u[i]]+w[i])flag = 1;
        if(flag)cout<<"flag was here 
     and this graph has the ---
    ";
        return 0;
    }

    五、bellman-ford

    讲道理的说

    本题code

    六、习题集

    0x09漫水填充

    一、题型分析

    用于DFS求联通块

    二、例题

    poj2486

    题目(待翻译):Due to recent rains, water has pooled in various places in Farmer John's field, which is represented by a rectangle of N x M (1 <= N <= 100; 1 <= M <= 100) squares. Each square contains either water ('W') or dry land ('.'). Farmer John would like to figure out how many ponds have formed in his field. A pond is a connected set of squares with water in them, where a square is considered adjacent to all eight of its neighbors. 
    Given a diagram of Farmer John's field, determine how many ponds he has.
    输入:
    10 12
    W........WW.
    .WWW.....WWW
    ....WW...WW.
    .........WW.
    .........W..
    ..W......W..
    .W.W.....WW.
    W.W.W.....W.
    .W.W......W.
    ..W.......W.
    输出:
    3
    //poj2386 - Lake Counting
    #include<iostream>
    #include<string>
    using namespace std;
    
    int n, m, ans;
    string a[100];
    
    void dfs(int x, int y){
        for(int i = -1; i <= 1; i++)
            for(int j = -1; j <= 1; j++)
                if(x+i>=0&&x+i<n&&y+j>=0&&y+j<m && a[x+i][y+j]=='W')
                    { a[x+i][y+j]='.'; dfs(x+i, y+j);}
    }
    
    int main(){
        cin>>n>>m;
        cin.get();
        for(int i = 0; i < n; i++)getline(cin, a[i]);
        for(int i = 0; i < n; i++)
            for(int j = 0; j < m; j++)
                if(a[i][j] == 'W'){ dfs(i, j); ans++;}
        cout<<ans<<"
    ";
        return 0;
    }

    UVa572

    题目:输入一个m行n列的字符矩阵,统计“@”组成多少个八连通块。
    输入:
    5 5
    ****@
    *@@*@
    *@**@
    @@@*@
    @@**@
    0 0
    输出:
    2
    #include<iostream>
    #include<string>
    using namespace std;
    
    int m, n;  string a[110];
    
    const int dx[] = {0,0,-1,1,-1,1,-1,1};
    const int dy[] = {1,-1,0,0,-1,1,1,-1};
    void dfs(int x, int y){
        a[x][y] = '*';
        for(int i = 0; i < 8; i++)
            if(x+dx[i]>=0 && x+dx[i]<m && y+dy[i]>=0 && y+dy[i]<n && a[x+dx[i]][y+dy[i]]=='@')
                dfs(x+dx[i],y+dy[i]);
    }
    
    int main(){
        while(cin>>m>>n &&m &&n){
            for(int i = 0; i < m; i++)cin>>a[i];
            int ans = 0;
            for(int i = 0; i < m; i++)
                for(int j = 0; j < n; j++)
                    if(a[i][j] == '@'){ dfs(i,j); ans++;}
            cout<<ans<<"
    ";
        }
        return 0;
    }

    0x0A全排列问题

    一、题目:

    题目:给出一个n, 请输出n的所有全排列。
    输入:
    3
    输出:
    1 2 3
    1 3 2
    2 1 3
    2 3 1
    3 1 2
    3 2 1

    二、分析

    1.
    2.
    3.

    三、提交

    Codevs1294: http://codevs.cn/problem/1294/

    四、解答:

    解法一、

    #include<cstdio>
    int n, a[10];
    void dfs(int cur){
        if(cur == n){
            for(int i = 0; i < n-1; i++)printf("%d ", a[i]);
            printf("%d
    ", a[n-1]);
        }else for(int i = 1; i <= n; i++){
            bool ok = true;
            for(int j = 0; j < cur; j++)
                if(a[j] == i)ok = false;
            if(ok){
                a[cur] = i;
                dfs(cur+1);
            }
        }
    }
    int main(){
        scanf("%d", &n);
        dfs(0);
        return 0;
    }

    解法二、

    #include<iostream>
    using namespace std;
    int n, a[20], book[20];
    void dfs(int cur){
        if(cur == n){
            for(int i = 0; i < n; i++)cout<<a[i]<<" ";
            cout<<"
    ";
        }else for(int i = 1; i <= n; i++)if(!book[i]){
            a[cur] = i;
            book[i] = 1;
            dfs(cur+1);
            book[i] = 0;
        }
    }
    int main(){
        cin>>n;
        dfs(0);
        return 0;
    }
  • 相关阅读:
    Flex上传文件报“Error #2038”
    AMQ9558
    perl 运算符
    linux gdm 远程桌面访问
    perl 捕获变量
    android apk嵌套 从一个apk启动另外一个apk
    apk调用另一个apk
    ORA-01591 锁被未决分布式事务处理
    jQuery事件控制点击内容下拉
    作业还是作孽?——Leo鉴书79
  • 原文地址:https://www.cnblogs.com/gwj1314/p/9444890.html
Copyright © 2020-2023  润新知