常用模板

关键词: 后缀数组  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;  
原文地址:https://www.cnblogs.com/aaronzlq/p/2941323.html