最短路、KMP、MST、并查集、线段树

最短路

hdu2544

  • dijkstra找距离当前点中未被刷新过距离起点最值的最小值(!vis[j] && min(d[j]))拿来刷新到其他点的距离
  • 如果d[v] + mp[v][j] < d[j]就刷新到j点的距离,j点要是未被刷新的点。

(对于邻接矩阵的理解:找于当前的所有(还没有算出最小值的点)里边的最小值,然后再通过找到这个最小值的点去刷新其他(还没有算出最小值)的点的最小值)
(对于表的理解:找当前边里点u的所有点v,也就是v属于u的所有邻接点,然后找到了距离最小的min_v,然后遍历min_v相邻的所有点,刷新最小值。)

void dijkstra(){
	for (int i = 0; i < n; i++) d[i] = mp[0][i];
    vis[0] = 1;
    for (int i = 0; i < n; i++) {
        tem = INF;v = 0;
        for (int j = 0; j < n; j++)
            if (!vis[j] && d[j] <= tem){
                tem = d[j];
                v = j;
            }
        vis[v] = 1;
        for (int j = 0; j < n; j++)
            if (!vis[j] && d[v]+mp[v][j] < d[j])
                d[j] = d[v]+mp[v][j];
    }
}

KMP

hdu1711

  • 获取nt数组
    • 作用是节省匹配字串回到最初
    • 获取是通过两个索引(都在匹配串)同时后移,如果相同就更新后面索引的nt为前面索引,如果不同的或前面的索引复制为索引的nt。
  • 使用nt数组
    • 是通过两个索引(分别在原串和在匹配串)同时后移动,如果相同就后移,如果不同就把匹配串挪到nt处。
  • 返回结果
    • 如果要首次匹配成功:把返回条件写在循环的里边或外边都可以,直接return即可
    • 如果要最后一次匹配成功:在循环里边加如果匹配串的索引到了匹配成功的位置,就记录(然后最后输出那个最后的索引),并归零或者回到nt索引处,归零是完全匹配个数(aaa 匹配aa 只有一个),回到nt索引是部分匹配(aaa 匹配aa可以得到两个)。
//
//  main.cpp
//  KMP复习
//
//  Created by 陈冉飞 on 2020/4/7.
//  Copyright © 2020 陈冉飞. All rights reserved.
//

#include 
using namespace std;
#define maxn 1000100
int nt[10010],a[maxn],b[10010],T,n,m,cnt;
#include 
#define cl(a,b) memset(a,b,sizeof(a))
#include 
vector<int> indexVec;

void getnt(){
    int i = 0,j = -1;nt[0] = -1;
    while (i < n) {
        if (j == -1 || b[i] == b[j]) {
            i++;j++;nt[i] = j;
        }else j = nt[j];
    }
}

int kmp(){
    getnt();
    int i = 0,j = 0;
    while (i < m && j < n) {
        if (j == -1 || a[i] == b[j]) {
            i++;j++;
        }else j = nt[j];
        if (j == n) {
            indexVec.push_back(i-j+1);
            cnt++;
//            j = 0; //完全匹配
            j = nt[j]; //交叉匹配
        }
    }
    // 首次匹配
    if (j == n) return i-j+1;
    
    return -1;
}

int main(int argc, const char * argv[]) {
    for (scanf("%d",&T); T; T--) {
        indexVec.clear();
        cl(a, 0);cl(b, 0);cnt = 0;
        scanf("%d%d",&m,&n);
        for (int i = 0; i < m; i++) scanf("%d",&a[i]);
        for (int i = 0; i < n; i++) scanf("%d",&b[i]);
//        printf("%d\n",kmp());
        kmp();
        for (int i = 0; i < indexVec.size(); i++) {
            printf("%d ",indexVec[i]);
        }
//        cout<
    }
    return 0;
}


//13 5
//1 2 1 2 3 1 2 3 1 2 2 1 2
//1 2 3 1 2

MST

  • prime:通过选定一个点(默认为起点),通过选取未被刷新最值的点中的最小距离!vis[j] && min(d[j])来作为mst展开的枝节。
  • 通过选定的枝节作为依据,刷新其他未刷新过的节点到枝节的距离d[j] > mp[v][j](不用再加上d[v]是因为已经在枝节内部)
//
//  main.cpp
//  MST复习
//
//  Created by 陈冉飞 on 2020/4/7.
//  Copyright © 2020 陈冉飞. All rights reserved.
//

#include 
using namespace std;
#define maxn 30
int mp[maxn][maxn],n,m,p,d[maxn],vis[maxn],tem,v,ans;
char s[10],t[10];
#define INF 0x3f3f3f
#include 
#define cl(a,b) memset(a,b,sizeof(a))

void prime(){
    for (int i = 0; i < n; i++) d[i] = mp[0][i];
    for (int i = 1; i < n; i++) {
        tem = INF;v = 0;vis[0] = 1;
        for (int j = 1; j < n; j++)
            if (!vis[j] && tem > d[j])
                tem = d[v = j];
        vis[v] = 1;ans += tem;
        for (int j = 1; j < n; j++)
            if (!vis[j] && d[j] > mp[v][j]) d[j] = mp[v][j];
    }
    printf("%d\n",ans);
}

int main(int argc, const char * argv[]) {
    while (~scanf("%d",&n) && n) {
        cl(d, 0);cl(vis, 0);ans = 0;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                if (i == j) mp[i][j] = 0;
                else mp[i][j] =INF;
        for (int i = 0; i < n-1; i++) {
            scanf("%s%d",s,&m);
            for (int j = 0; j < m; j++) {
                scanf("%s%d",t,&p);
                mp[s[0]-'A'][t[0]-'A'] = p;
                mp[t[0]-'A'][s[0]-'A'] = p;
            }
        }
        prime();
    }
    return 0;
}

并查集

  • fa[]数组用来维护集合
  • 通过findfa()来找属于那个集合
  • 合并的时候先看是否在一个集合中,如果不在的话然后更改其中的一个fa到另一个下。
//
//  main.cpp
//  并查集复习
//
//  Created by 陈冉飞 on 2020/4/7.
//  Copyright © 2020 陈冉飞. All rights reserved.
//

#include 
using namespace std;
#define maxn 1010
int T,fa[maxn],n,m,p,q;
#include 
unordered_set<int> c;

int findfa(int x){
    if (x == fa[x]) return x;
    return findfa(fa[x]);
}

void merge(int x,int y){
    if (findfa(x) != findfa(y)) fa[x] = findfa(y);
}

int main(int argc, const char * argv[]) {
    for (scanf("%d",&T); T; T--) {
        scanf("%d%d",&n,&m);
        for (int i = 0; i < n; i++) fa[i] = i;
        for (int i = 0; i < m; i++) {
            scanf("%d%d",&p,&q);
            merge(p,q);
        }
        for (int i = 0; i < n; i++)
            if (c.find(findfa(i+1)) == c.end())
                c.insert(findfa(i+1));
        printf("%d\n",c.size());
    }
    
    
    return 0;
}

线段树

  • 查询区间和=》分段查询
if (gl <= mid) ans += query(lson, gl, gr);
if (gr >= mid+1) ans += query(rson, gl, gr);
//
//  main.cpp
//  线段树复习
//
//  Created by 陈冉飞 on 2020/4/7.
//  Copyright © 2020 陈冉飞. All rights reserved.
//

#include 
using namespace std;
#include 
#define cl(a,b) memset(a,b,sizeof(a))
#define maxn 10010
int a[maxn<<2],b[5] = {1,2,3,4,5};
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r

// sum
void pushup(int k){a[k] = a[k<<1]+a[k<<1|1];}

void build(int k,int l,int r)
{
    if(l==r){a[k] = b[l-1];return;}
    int mid = (l+r)/2;
    build(lson);build(rson);
    pushup(k);
}

int query(int k,int l,int r,int gl,int gr){
    if (gl <= l && r <= gr) return a[k];
    int mid = (l+r)/2,ans = 0;
    if (gl <= mid) ans += query(lson, gl, gr);
    if (gr >= mid+1) ans += query(rson, gl, gr);
    return ans;
}

void update(int k,int l,int r,int pos,int val){
    if (l == r && l == pos) {a[k] = val;return;}
    int mid = (l+r)/2;
    if (mid >= pos) update(lson, pos, val);
    else if (mid+1 <= pos) update(rson, pos, val);
    pushup(k);
}

int main(int argc, const char * argv[]) {
    build(1, 1, 5);
    cout<<query(1, 1, 5, 2, 4)<<endl;
    update(1, 1, 5, 3, 1);
    cout<<query(1, 1, 5, 2, 4)<<endl;
    return 0;
}
//1 2 3 4 5

你可能感兴趣的:(ACM)