zoukankan      html  css  js  c++  java
  • 常用模板

    关键词: 后缀数组  AC自动机   AC+dp    分数规划    二分图最小权    二分图最大权  2-sat    最大流     最短路径(负环判定)    

    最小生成树(kruskal、并查集)    最小生成树prim    stl优先队列的简单用法   二分图最大匹配     康托展开  最小费用(最大)流    日期

    kd树

    1.后缀数组

    #include <cstdio>
    #include <string>
    #include <vector>
    #include <cstring>
    #include <utility>
    #include <algorithm>
    using namespace std;
    
    const int MAXN = 100005;
    
    int sa[MAXN], rank[MAXN], height[MAXN];
    char str[MAXN];
    
    int wa[MAXN], wb[MAXN], wv[MAXN], ws[MAXN];
    inline bool cmp(int *r, int a, int b, int len){
        return (r[a]==r[b]) && (r[a+len]==r[b+len]);
    }
    
    void sortSA(char *r, int *sa, int n, int m){//r为字符串数组,sa为后缀数组,n=strlen(s)+1,m为max(r[i])+1。
        int i, j, p, *x = wa, *y = wb, *t;
        //对长度为1的字符串基数排序。
        for(i = 0; i < m; i++)
            ws[i] = 0;//清零。
        for(i = 0; i < n; i++)
            ws[x[i]=r[i]]++;//统计各相同字符的个数。
        for(i = 1; i < m; i++)
            ws[i] += ws[i-1];//统计小于等于i的字符共有多少个。
        for(i = n-1; i >= 0; i--)
            sa[--ws[x[i]]] = i;//小于等于r[i]共有ws[x[i]]个,因此r[i]排在第ws[x[i]]个。
    
        for(j = p = 1; p < n; j <<= 1, m = p){//p是第二关键字为0的个数,j是当前比较的字符串长度.
            //对第二关键字基数排序。
            //y[s]=t表示排在第s个的起点在t,即y[s]对第二关键字排序,但y[s]的值指向第一关键字的位置。
            for(p=0, i=n-j; i < n; i++)
                y[p++] = i;//在n-j之后的第二关键字都为0,排在前面,即第p个。
            for(i = 0; i < n; i++){
                if(sa[i] >= j)//如果排在第i个的字符串起点在sa[i],满足sa[i]>=当前字符串长度j。
                    y[p++] = sa[i] - j;//对于sa[i]-j为起点的第二关键字排在前面。
            }
            //对第一关键字基数排序。
            for(i = 0; i < m; i++)
                ws[i] = 0;//清零。
            for(i = 0; i < n; i++)
                ws[wv[i]=x[y[i]]]++;//第二关键字排在第i个的起点在y[i],x[y[i]]就是y[i]指向的字符,ws进行个数统计。
            for(i = 1; i < m; i++)
                ws[i] += ws[i-1];//统计字符小于等于i的个数。
            for(i = n-1; i >= 0; i--)//wv[i]是排在第i个第二关键字对应的第一关键字。
                sa[--ws[wv[i]]] = y[i];//y[i]就是第一关键字的位置。
            for(t=x,x=y,y=t,x[sa[0]]=0,p=i=1; i < n; i++)//交换x,y的地址,x保存当前rank值,y为前一次rank值。
                x[sa[i]]=cmp(y,sa[i-1],sa[i],j) ? p-1:p++;
            //若rank[sa[i-1]]=rank[sa[i]],则必然sa[i-1]+j没有越界,因为不可能有相等的后缀。
        }
    }
    
    /*height 数组:定义height[i]=suffix(sa[i-1])和suffix(sa[i])的最长公
    共前缀,也就是排名相邻的两个后缀的最长公共前缀。那么对于j 和k,不妨设
    rank[j]<rank[k],则有以下性质:
    suffix(j) 和suffix(k) 的最长公共前缀为height[rank[j]+1],
    height[rank[j]+2], height[rank[j]+3], … ,height[rank[k]]中的最小值。
    */
    
    void calHeight(char *r, int *sa, int n){  //n为字符数组r的长度
        int i, j, k = 0;
        for(i = 1; i <= n; i++)  rank[sa[i]] = i;
        for(i = 0; i < n; i++){
            for(k? k--:0, j=sa[rank[i]-1]; r[i+k]==r[j+k]; k++);
            height[rank[i]] = k;
        }
    }
    
    int main()
    {
        freopen("data.in", "r", stdin);
        scanf("%s", str);
        int len = strlen(str);
        sortSA(str, sa, len+1, 255);
        calHeight(str, sa, len);
        printf("%s\n", str);
        for(int i = 1; i <= len; i++)  printf("%d ", sa[i]); printf("\n");
        for(int i = 1; i <= len; i++)  printf("%d ", height[i]); printf("\n");
        return 0;
    }

    2.AC自动机

    struct node {
        int ct;
        node *pre, *next[26];
        void init() {
            ct = 0;
            pre = 0;
            memset(next, 0, sizeof(next));
        }
    };
    
    int cnt; //节点总数
    node *root, trie[500010];
    
    node *queue[500010];
    
    void insertStr(node *root, char *str) {
        int index, len = strlen(str);
        for(int i = 0; i < len; i++) {
            index = str[i]-'a';
            if(root->next[index] == 0) {
                root->next[index] = &trie[++cnt];
                root->next[index]->init();
            }
            root = root->next[index];
        }
        root->ct++;
    }
    
    void buildAC() {
        int head, tail;
        node *u, tmp;
        queue[0] = root;
        root->pre = root;
        head = tail = 0;
        while(head <= tail) {
            u = queue[head++];
            for(int i = 0; i < 26; i++) {
                if(u->next[i] == 0) {
                    if(u == root)  u->next[i] = root;
                    else  u->next[i] = u->pre->next[i];
                }
                else {
                    if(u == root)  u->next[i]->pre = root;
                    else  u->next[i]->pre = u->pre->next[i];
                    queue[++tail] = u->next[i];
                }
            }
        }
    }

    3.AC+dp

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <map>
    #include <string>
    #include <utility>
    #include <algorithm>
    using namespace std;
    
    const int N = 10;
    
    struct node {
        int num, index;
        node *pre, *next[4];
        void init() {
            num = index = 0;
            pre = 0;
            memset(next, 0, sizeof(next));
        }
    };
    
    int n, l, cnt, val[10], sval[1<<N];
    bool dp[2][N*150][1<<N];
    char str[150];
    
    map <char, int> h;
    node trie[N*150];
    node *root, *queue[N*150];
    
    void insertStr(node *root, char *str, int pos) {
        int lab, len = strlen(str);
        for(int i = 0; i < len; i++) {
            lab = h[str[i]];
            if(root->next[lab] == NULL) {
                root->next[lab] = &trie[++cnt];
                root->next[lab]->init();
                root->next[lab]->index = cnt;
            }
            root = root->next[lab];
        }
        root->num |= (1<<pos);
    }
    
    void buildAC() {
        int head, tail;
        node *u;
        root->pre = root;
        head = tail = 0;
        queue[0] = root;
        while(head <= tail) {
            u = queue[head++];
            u->num |= u->pre->num;
            for(int i = 0; i < 4; i++) {
                if(u->next[i] == 0) {
                    if(u == root)  u->next[i] = root;
                    else  u->next[i] = u->pre->next[i];
                }
                else {
                    if(u == root)  u->next[i]->pre = root;
                    else  u->next[i]->pre = u->pre->next[i];
                    queue[++tail] = u->next[i];
                }
            }
        }
    }
    
    int main() {
        //freopen("data.in", "r", stdin);
        h['A'] = 0; h['G'] = 1; h['T'] = 2; h['C'] = 3;
        while(scanf("%d%d", &n, &l) != EOF) {
            memset(trie, 0, sizeof(trie));
            root = &trie[0];
            root->init();
            cnt = 0;
            for(int i = 0; i < n; i++) {
                scanf(" %s%d", str, &val[i]);
                insertStr(root, str, i);
            }
            memset(sval, 0, sizeof(sval));
            for(int state = 0; state < (1<<n); state++) {
                for(int j = 0; j < n; j++)
                    if(state&(1<<j))
                        sval[state] += val[j];
            }
            buildAC();
            memset(dp, false, sizeof(dp));
            int u, v;
            u = 0;
            dp[u][0][0] = true;
            for(int i = 0; i < l; i++) {
                v = u^1;
                memset(dp[v], false, sizeof(dp[v]));
                for(int j = 0; j <= cnt; j++)
                    for(int k = 0; k < (1<<n); k++) {
                        if(!dp[u][j][k])  continue;
                        else {
                            for(int p = 0; p < 4; p++) {
                                int dindex = trie[j].next[p]->index;
                                dp[v][dindex][k|trie[dindex].num] = true;
                            }
                        }
                    }
                u = v;
            }
            int ans = -1;
            for(int i = 0; i <= cnt; i++)
                for(int j = 0; j < (1<<n); j++) {
                    if(dp[u][i][j] == false)  continue;
                    ans = max(ans, sval[j]);
                }
            if(ans != -1)  printf("%d\n", ans);
            else  printf("No Rabbit after 2012!\n");
        }
        return  0;
    }

    4.分数规划

    1) 一般分数规划的解法
    简单总结一下解分数规划的一般步骤吧:
    1.  对于最小化目标函数r = ax/bx,则构造函数g(r)=min{ax - r*bx}
         对于最大化目标函数r = ax/bx,则构造函数g(r)=max{ax - r*bx}
    2.  由各种大科学家大神们证明得结论T_T:
         (1)g(r)是单调减函数(有些离散情况下也有可能是单调不增加函数),即随r的增加而减小。 
         (2)若r是最优解,则g(r)==0。。
    3.  建立模型二分r求解。

    5.二分图最小权

    #include <iostream>
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <utility>
    using namespace std;
    
    const int N =105;
    const int M =10005;
    const int inf =0x1fffffff;
    
    int n, m, tot, lx[N], ly[N], match[N], h[N], v[M], w[M], nxt[M];
    bool visx[N], visy[N];
    int lack;
    
    void add(int a, int b, int c)
    {
        v[tot] = b;
        w[tot] = c;
        nxt[tot] = h[a];
        h[a] = tot++;
    }
    
    bool find(int u)
    {
        int i, t;
        visx[u] =true;
        for(i = h[u]; i !=-1; i = nxt[i])
            if(!visy[v[i]])
            {
                t = w[i] - lx[u] - ly[v[i]];
                if(t ==0)
                {
                    visy[v[i]] =true;
                    if(match[v[i]]==-1|| find(match[v[i]]))
                    {
                        match[v[i]] = u;
                        return  true;
                    }
                }
                else if(t >0)
                    lack = min(lack, t);
            }
        return  false;
    }
    
    int calMatch(int n) {
        int ans = 0;
        for(int i =1; i <= n; i++)
        {
            lx[i] = inf;
            ly[i] =0;
            for(int j = h[i]; j !=-1; j = nxt[j])
                lx[i] = min(lx[i], w[j]);
        }
        memset(match, -1, sizeof(match));
        for(int i =1; i <= n; i++)
        {
            memset(visx, false, sizeof(visx));
            memset(visy, false, sizeof(visy));
            lack = inf;
            while(!find(i))
            {
                for(int j =1; j <= n; j++)
                {
                    if(visx[j])  lx[j] += lack;
                    if(visy[j])  ly[j] -= lack;
                }
                memset(visx, false, sizeof(visx));
                memset(visy, false, sizeof(visy));
            }
        }
        ans = 0;
        for(int i =1; i <= n; i++)  ans = ans + lx[i] + ly[i];
        return  ans;
    }

    6.二分图最大权

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    usingnamespace std;
    
    constint N =310;
    constint inf =0x1fffffff;
    
    int n, lx[N], ly[N], match[N], w[N][N];
    bool visx[N], visy[N];
    int lack;
    
    int getNum()
    {
        char c;
        int ans =0;
        c = getchar();
        while(c<'0'|| c>'9') c = getchar();
        while(c>='0'&& c<='9')
        {
            ans = ans*10+c-'0';
            c = getchar();
        }
        return  ans;
    }
    
    bool find(int u)
    {
        int i, t;
        visx[u] =true;
        for(i =1; i <= n; i++)
            if(!visy[i])
            {
                t = lx[u] + ly[i] - w[u][i];
                if(t ==0)
                {
                    visy[i] =true;
                    if(match[i]==-1|| find(match[i]))
                    {
                        match[i] = u;
                        returntrue;
                    }
                }
                elseif(t >0)
                    lack = min(lack, t);
            }
        returnfalse;
    }
    
    int main()
    {
        int i, j, ans;
        while(scanf("%d", &n) != EOF)
        {
            for(i =1; i <= n; i++)
            {
                lx[i] = ly[i] =0;
                for(j =1; j <= n; j++)
                {
                    w[i][j] = getNum();
                    lx[i] = max(lx[i], w[i][j]);
                }
            }
            memset(match, -1, sizeof(match));
            for(i =1; i <= n; i++)
            {
                memset(visx, false, sizeof(visx));
                memset(visy, false, sizeof(visy));
                lack = inf;
                while(!find(i))
                {
                    for(j =1; j <= n; j++)
                    {
                        if(visx[j])  lx[j] -= lack;
                        if(visy[j])  ly[j] += lack;
                    }
                    memset(visx, false, sizeof(visx));
                    memset(visy, false, sizeof(visy));
                }
            }
            ans =0;
            for(i =1; i <= n; i++)  ans = ans + lx[i] + ly[i];
            printf("%d\n", ans);
        }
        return0;
    }

    7. 2-sat

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    const int N = 1010;
    
    int n; //原图中共有2*n个相对的节点。
    int ct, depth, top, index[N<<1], d[N<<1], low[N<<1], stack[N<<1];
    bool instack[N<<1], map[N<<1][N<<1], g[N<<1][N<<1];
    
    int tot, et[N<<1], color[N<<1], op[N<<1];
    bool visit[N<<1];
    
    void initData() { //初始化数据,根据题意建图,建好的初始图为map
        ........
    }
    
    void dfs(int u) {    //tarjan求强连通分量,缩点
        int i, x;
        d[u] = low[u] = depth++;
        stack[++top] = u;
        instack[u] =true;
        for(i = 0; i < n+n; i++)
            if(map[u][i]) {
                if(d[i] == -1) {
                    dfs(i);
                    low[u] = min(low[u], low[i]);
                }
                else {
                    if(instack[i])
                        low[u] = min(low[u], d[i]);
                }
            }
        if(low[u] == d[u]) {
            ct++;
            while(top)
            {
                x = stack[top--];
                instack[x] = false;
                index[x] = ct;
                if(x == u)  break;
            }
        }
    }
    
    void buildNewGraph() {  //根据缩点建立新图
        int i, j;
        memset(g, false, sizeof(g));
        for(i = 0; i < n+n; i++)
            for(j = 0; j < n+n; j++)
                if(map[i][j])
                    g[index[i]][index[j]] = true;
        for(i = 1; i <= ct; i++)
            for(j = i+1; j <= ct; j++)
                swap(g[i][j], g[j][i]);   //将新图中的边反向
        for(i = 0; i < n; i++) {      //根据原图的矛盾节点确定新图的矛盾节点
            op[index[i]] = index[i+n];
            op[index[i+n]] = index[i];
        }
    }
    
    void transDfs(int u) {
        int i;
        visit[u] =true;
        for(i = 1; i <= ct; i++)
            if(!visit[i] && g[u][i])
                transDfs(i);
        et[++tot] = u;
    }
    
    void colorDfs(int u) {
        int i;
        color[u] = 0;
        for(i = 1; i <= ct; i++)
            if(color[i]==-1 && g[u][i])
                colorDfs(i);
    }
    
    void generateAns() {
        int i;
        memset(visit, false, sizeof(visit));
        tot = 0;
        //拓扑排序
        for(i = 1; i <= ct; i++)
            if(!visit[i])
                transDfs(i);
        memset(color, -1, sizeof(color));
        for(i = ct; i > 0; i--)
            if(color[et[i]] == -1) {
                color[et[i]] = 1;
                //选择第一个未着色的顶点x, 把x染成红色1, 并把与之矛盾的节点y及其所有子孙节点染成蓝色0。
                colorDfs(op[et[i]]);
            }
    }
    
    void solve() {
        int i;
        depth = top = ct =0;
        memset(d, -1, sizeof(d));
        memset(instack, false, sizeof(instack));
        for(i = 0; i < n+n; i++)
            if(d[i] == -1)
                dfs(i);
        for(i = 0; i < n; i++)
            if(index[i] == index[i+n])
                break;
        if(i < n)  printf("NO\n");
        else {
            printf("YES\n");
            buildNewGraph();
            generateAns();
            //printAns();
        }
    }
    
    int main()
    {
        initData();
        solve();
        return  0;
    }

    8. 最大流

    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <cstring>
    #include <utility>
    #include <algorithm>
    using namespace std;
    
    const int Maxn = 20005;
    const int Maxm = (200005<<1)+(Maxn<<1);
    const int inf = 0x1fffffff;
    
    int n, m, queue[Maxn], lab[Maxn];
    int tot, h[Maxn], nxt[Maxm<<1], v[Maxm<<1], res[Maxm<<1];
    
    void addEdge(int a, int b, int c) {
        v[tot] = b; res[tot] = c; nxt[tot] = h[a]; h[a] = tot++;
        v[tot] = a; res[tot] = 0; nxt[tot] = h[b]; h[b] = tot++;
    }
    
    bool bfs(int s, int t) {
        int head, tail, u;
        memset(lab, -1, sizeof(lab));
        lab[s] = head = tail =0;
        queue[0] = s;
        while(head <= tail) {
            u = queue[head++];
            for(int i = h[u]; i != -1; i = nxt[i])
                if(res[i]>0 && lab[v[i]]==-1) {
                    lab[v[i]] = lab[u] +1;
                    queue[++tail] = v[i];
                }
        }
        if(lab[t] != -1)  return  true;
        else  return  false;
    }
    
    int dinicDfs(int delta, int u, int t) {
        int sum =0, tmp;
        if(u == t)  return  delta;
        else {
            for(int i = h[u]; i != -1; i = nxt[i])
                if(lab[v[i]]==lab[u]+1 && res[i]>0) {
                    tmp = dinicDfs(min(delta, res[i]), v[i], t);
                    sum += tmp;
                    delta -= tmp;
                    res[i] -= tmp;
                    res[i^1] += tmp;
                    if(delta == 0)  break;
                }
            if(sum == 0)  lab[u] = -1;
            return  sum;
        }
    }
    
    int maxFlow(int s, int t) {
        int ans =0;
        while(bfs(s, t))
            ans += dinicDfs(inf, s, t);
        return  ans;
    }
    
    int main()
    {
        int a, b, c, s, t;
        freopen("data.txt", "r", stdin);
        while(scanf("%d%d", &n, &m) != EOF) {
            s = 0; t = n+1;
            tot = 0;
            for(int i = 0; i <= t; i++)  h[i] = -1;
            for(int i = 1; i <= n; i++) {
                scanf("%d%d", &a, &b);
                addEdge(s, i, a); addEdge(i, t, b);
            }
            while(m--) {
                scanf("%d%d%d", &a, &b, &c);
                addEdge(a, b, c); addEdge(b, a, c);
            }
            int ans = maxFlow(s, t);
            cout << ans << endl;
        }
        return  0;
    }

    9.最短路径(spfa判负环)

    #include <iostream>
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <queue>
    #include <algorithm>
    using namespace std;
    
    const int N = 550;
    const int M = 3000<<1;
    
    int Case, n, m, w;
    int tot, h[N], nxt[M], c[M], v[M];
    int used[N], dis[N];
    bool visit[N];
    
    void add(int s, int t, int e) {
        v[tot] = t; c[tot] = e;
        nxt[tot] = h[s]; h[s] = tot++;
    }
    
    bool spfa(int s) {
        int u;
        queue <int> q; while(!q.empty())  q.pop();
        memset(visit, false, sizeof(visit));
        memset(used, 0, sizeof(used));
        for(int i = 1; i <= n; i++)  dis[i] = 0x1fffffff; dis[0] = 0;
        used[0] = 1;
        q.push(s);
        while(!q.empty()) {
            u = q.front(); q.pop();
            visit[u] = false;
            for(int p = h[u]; p != -1; p = nxt[p]) {
                if(dis[v[p]] > dis[u] + c[p]) {
                    dis[v[p]] = dis[u] + c[p];
                    if(!visit[v[p]]) {
                        visit[v[p]] = true;
                        q.push(v[p]);
                        used[v[p]]++;
                        if(used[v[p]] >= n)  return  true;
                    }
                }
            }
        }
        return  false;
    }
    
    int main() {
        int s, t, e;
        scanf("%d", &Case);
        while(Case--) {
            scanf("%d%d%d", &n, &m, &w);
            memset(h, -1, sizeof(h)); tot = 0;
            for(int i = 0; i < m; i++) {
                scanf("%d%d%d", &s, &t, &e);
                add(s, t, e);
                add(t, s, e);
            }
            for(int i = 0; i < w; i++) {
                scanf("%d%d%d", &s, &t, &e);
                add(s, t, -e);
            }
            for(int i = 1; i <= n; i++)  add(0, i, 0);
            if(spfa(0))  printf("YES\n");
            else  printf("NO\n");
        }
        return  0;
    }

     10. 最小生成树 (kruskal、并查集)

    #include <iostream>
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    const int N = 200010;
    
    struct node {
        int x, y, cost;
    }e[N];
    int n, m, father[N];
    
    bool cmp(const node &a, const node &b) {
        return  a.cost < b.cost;
    }
    
    int getFather(int u) {
        if(father[u] != u)  father[u] = getFather(father[u]);
        return  father[u];
    }
    
    int kruskal() {
        int fa, fb, sum = 0;
        for(int i = 0; i < n; i++)  father[i] = i;
        sort(e, e+m, cmp);
        for(int i = 0; i < m; i++) {
            fa = getFather(e[i].x); fb = getFather(e[i].y);
            if(fa == fb)  continue;
            else {
                father[fb] = father[fa];
                sum += e[i].cost;
            }
        }
        return  sum;
    }
    
    int main() {
        int tot;
        freopen("data.in", "r", stdin);
        while(scanf("%d%d", &n, &m) != EOF) {
            if(n==0 && m==0)  break;
            tot = 0;
            for(int i = 0; i < m; i++) {
                scanf("%d%d%d", &e[i].x, &e[i].y, &e[i].cost);
                tot += e[i].cost;
            }
            int ans = tot-kruskal();
            printf("%d\n", ans);
        }
        return  0;
    }

     11.最小生成树prim

    #include <iostream>
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <queue>
    #include <algorithm>
    using namespace std;
    
    const int N = 105;
    
    int Case, n;
    bool visit[N];
    double x[N], y[N], dis[N], g[N][N];
    
    double Cal(int a, int b) {
        double tx=x[a]-x[b], ty=y[a]-y[b];
        return  sqrt(tx*tx + ty*ty);
    }
    
    double prim() {
        double tot = 0.0, min;
        int v;
        for(int i = 1; i <= n; i++)  dis[i] = g[1][i];
        memset(visit, false, sizeof(visit));
        visit[1] = true;
        for(int k = 1; k < n; k++) {
            min = 1e8;
            for(int i = 1; i <= n; i++) {
                if(!visit[i] && min>dis[i]) {
                    min = dis[i];
                    v = i;
                }
            }
            visit[v] = true;
            for(int i = 1; i <= n; i++) {
                if(!visit[i] && dis[i]>g[v][i]) {
                    dis[i] = g[v][i];
                }
            }
            tot += min;
        }
        return  tot;
    }
    
    int main() {
        freopen("data.in", "r", stdin);
        scanf("%d", &Case);
        while(Case--) {
            scanf("%d", &n);
            for(int i = 1; i <= n; i++)  scanf("%lf%lf", &x[i], &y[i]);
            for(int i = 1; i <= n; i++) {
                g[i][i] = 0.0;
                for(int j = i+1; j <= n; j++) {
                    g[i][j] = g[j][i] = Cal(i, j);
                }
            }
            double ans = prim();
            printf("%.2f\n", ans);
            if(Case)  printf("\n");
        }
        return  0;
    }

    12. stl优先队列的简单用法

    #include <iostream>
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <queue>
    #include <algorithm>
    using namespace std;
    
    struct comp {
        bool operator () (int a, int b) {
            return  a > b;
        }
    };
    
    int main() {
        freopen("data.in", "r", stdin);
        priority_queue <int, vector<int>, comp> q;
        q.push(11); q.push(0); q.push(22); q.push(16); q.push(6); q.push(8); q.push(100);
        while(!q.empty()) {
            int x = q.top(); q.pop();
            cout << x << endl;
        }
        return  0;
    }
    
    输出:
    0
    6
    8
    11
    16
    22
    100

     13. 二分图最大匹配

    #include <iostream>
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    const int N = 105;
    const double eps = 1e-6;
    
    struct node {
        double x, y;
    };
    
    int n, m, s, v, match[N];
    bool visit[N], g[N][N];
    node c[N], h[N];
    
    double Cal(const node &a, const node &b) {
        double tx, ty;
        tx = a.x-b.x; ty = a.y-b.y;
        return  sqrt(tx*tx+ty*ty);
    }
    
    int cmp(double x) {
        if(x > eps)  return  1;
        else if(x < -eps)  return  -1;
        else  return  0;
    }
    
    bool find(int u) {
        for(int i = 0; i < m; i++) {
            if(g[u][i] && !visit[i]) {
                visit[i] = true;
                if(match[i]==-1 || find(match[i])) {
                    match[i] = u;
                    return  true;
                }
            }
        }
        return  false;
    }
    
    int maxMatch() {
        int ans = 0;
        memset(match, -1, sizeof(match));
        for(int i = 0; i < n; i++) {
            if(find(i))  ans++;
            memset(visit, false, sizeof(visit));
        }
        return  ans;
    }
    
    int main() {
        double tmp;
        while(scanf("%d%d%d%d", &n, &m, &s, &v) != EOF) {
            for(int i = 0; i < n; i++)  scanf("%lf%lf", &c[i].x, &c[i].y);
            for(int i = 0; i < m; i++)  scanf("%lf%lf", &h[i].x, &h[i].y);
            memset(g, false, sizeof(g));
            for(int i = 0; i < n; i++)
                for(int j = 0; j < m; j++) {
                    tmp = Cal(c[i], h[j]);
                    if(cmp(tmp/v - s) < 0)  g[i][j] = true;
                }
            int mm = maxMatch();
            printf("%d\n", n-mm);
        }
        return  0;
    }

     14. 康托展开

    #include <iostream>
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    const int N = 10;
    
    int p[N], fac[N];
    
    int Cal(int p[], int n) {
        int ans = 0;
        for(int i = 0; i < n; i++) {
            int ct = 0;
            for(int j = i+1; j < n; j++) {
                if(p[j] < p[i])  ct++;
            }
            ans += ct*fac[n-i-1];
        }
        return  ans+1;
    }
    
    int main() {
        int n;
        fac[0] = 1;
        for(int i = 1; i < N; i ++)  fac[i] = fac[i-1]*i;
        while(cin >> n) {
            for(int i = 0; i < n; i++)  cin >> p[i];
            int ans = Cal(p, n);
            cout << ans << endl;
        }
        return  0;
    }

    15. 最小费用(最大)流

    #include <iostream>
    #include <algorithm>
    #include <string>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <vector>
    #include <cmath>
    using namespace std;
    int sumFlow;
    const int MAXN = 1010;
    const int MAXM = 1000200;
    const int INF = 1000000000;
    struct Edge
    {
        int u, v, cap, cost;
        int next;
    }edge[MAXM<<2];
    int NE;
    int head[MAXN], dist[MAXN], pp[MAXN];
    bool vis[MAXN];
    void init()
    {
        NE = 0;
        memset(head, -1, sizeof(head));
    }
    void addedge(int u, int v, int cap, int cost)
    {
        edge[NE].u = u; edge[NE].v = v; edge[NE].cap = cap; edge[NE].cost = cost;
        edge[NE].next = head[u]; head[u] = NE++;
        edge[NE].u = v; edge[NE].v = u; edge[NE].cap = 0; edge[NE].cost = -cost;
        edge[NE].next = head[v]; head[v] = NE++;
    }
    bool SPFA(int s, int t, int n)
    {
        int i, u, v;
        queue <int> qu;
        memset(vis,false,sizeof(vis));
        memset(pp,-1,sizeof(pp));
        for(i = 0; i <= n; i++) dist[i] = INF;
        vis[s] = true; dist[s] = 0;
        qu.push(s);
        while(!qu.empty())
        {
            u = qu.front(); qu.pop(); vis[u] = false;
            for(i = head[u]; i != -1; i = edge[i].next)
            {
                v = edge[i].v;
                if(edge[i].cap && dist[v] > dist[u] + edge[i].cost)
                {
                    dist[v] = dist[u] + edge[i].cost;
                    pp[v] = i;
                    if(!vis[v])
                    {
                        qu.push(v);
                        vis[v] = true;
                    }
                }
            }
        }
        if(dist[t] == INF) return false;
        return true;
    }
    int MCMF(int s, int t, int n) // minCostMaxFlow
    {
        int flow = 0; // 总流量
        int i, minflow, mincost;
        mincost = 0;
        while(SPFA(s, t, n))
        {
            minflow = INF + 1;
            for(i = pp[t]; i != -1; i = pp[edge[i].u])
                if(edge[i].cap < minflow)
                    minflow = edge[i].cap;
            flow += minflow;
            for(i = pp[t]; i != -1; i = pp[edge[i].u])
            {
                edge[i].cap -= minflow;
                edge[i^1].cap += minflow;
            }
            mincost += dist[t] * minflow;
        }
        sumFlow = flow; // 最大流
        return mincost;
    }

     16. 日期

    int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    class Date {
    public:
        //判断是否闰年
        inline static bool isLeap(int year) {
            return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
        }
        int year, month, day;
        Date() {}
        Date(int y, int m, int d) : year(y), month(m), day(d) {}
        //判断日期是否合法
        inline bool isLegal() const {
            if (month <= 0 || month > 12) {
                return false;
            }
            if (month == 2) {
                return day > 0 && day <= 28 + isLeap(year);
            }
            return day > 0 && day <= days[month - 1];
        }
        //与另一个日期比较
        inline int compareTo(const Date &other) const {
            if (year != other.year) {
                return year - other.year;
            }
            if (month != other.month) {
                return month - other.month;
            }
            return day - other.day;
        }
        //返回当前日期是星期几 0 (Sunday) ... 6 (Saturday)
        inline int toWeekday() const {
            int tm = month >= 3 ? (month - 2) : (month + 10);
            int ty = month >= 3 ? year : (year - 1);
            return (ty + ty / 4 - ty / 100 + ty / 400 + (int)(2.6 * tm - 0.2) + day) % 7;
        }
        //将日期转换为偏移量
        inline int toInt() const {
            int ret = year * 365 + (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400;
            days[1] += isLeap(year);
            for (int i = 0; i < month - 1; ret += days[i++]);
            days[1] = 28;
            return ret + day;
        }
        //根据给定的偏移量设置当前日期
        inline void fromInt(int a) {
            year = a / 146097 * 400;
            for (a %= 146097; a >= 365 + isLeap(year); a -= 365 + isLeap(year), year++);
            days[1] += isLeap(year);
            for (month = 1; a >= days[month - 1]; a -= days[month - 1], month++);
            days[1] = 28;
            day = a + 1;
        }
    };

    17. kd树

    #include <cmath>
    #include <queue>
    #include <algorithm>
    using namespace std;
    
    #define sqr(x) (x)*(x)  
    int k,n,idx;   //k为维数,n为点数  
    struct point  
    {  
        int x[K];  
        bool operator < (const point &u) const  
        {  
            return x[idx]<u.x[idx];  
        }  
    }po[N];  
      
    typedef pair<double,point>tp;  
    priority_queue<tp>nq;  
      
    struct kdTree  
    {  
        point pt[N<<2];  
        int son[N<<2];  
      
        void build(int l,int r,int rt=1,int dep=0)  
        {  
            if(l>r) return;  
            son[rt]=r-l;  
            son[rt*2]=son[rt*2+1]=-1;  
            idx=dep%k;  
            int mid=(l+r)/2;  
            nth_element(po+l,po+mid,po+r+1);  
            pt[rt]=po[mid];  
            build(l,mid-1,rt*2,dep+1);  
            build(mid+1,r,rt*2+1,dep+1);  
        }  
        void query(point p,int m,int rt=1,int dep=0)  
        {  
            if(son[rt]==-1) return;  
            tp nd(0,pt[rt]);  
            for(int i=0;i<k;i++) nd.first+=sqr(nd.second.x[i]-p.x[i]);  
            int dim=dep%k,x=rt*2,y=rt*2+1,fg=0;  
            if(p.x[dim]>=pt[rt].x[dim]) swap(x,y);  
            if(~son[x]) query(p,m,x,dep+1);  
            if(nq.size()<m) nq.push(nd),fg=1;  
            else  
            {
                if(nd.first<nq.top().first) nq.pop(),nq.push(nd);  
                if(sqr(p.x[dim]-pt[rt].x[dim])<nq.top().first) fg=1;  
            }
            if(~son[y]&&fg) query(p,m,y,dep+1); 
    
        }  
    }kd;  
  • 相关阅读:
    用javascript写星际飞机大战游戏
    Vue源码分析之实现一个简易版的Vue
    Vue源码分析之数据驱动
    Vue源码分析之虚拟DOM
    使用HbuilderX离线打包5+APP
    ERROR in build.js from UglifyJs
    PHP 的一些开发规范
    Markdown使用TOC自动生成导航栏
    Hexo博客skapp主题部署填坑指南
    Docker 官方安装详解
  • 原文地址:https://www.cnblogs.com/aaronzlq/p/2941323.html
Copyright © 2011-2022 走看看