kuangbin专题十一网络流总结

这个专题是之前做的专题中做的最轻松的,毕竟只要想出建图就ok了。
建图有两个套路。如果是对一条边限制的话,那么就可以直接把容量变成那个限制就行了。而对点有限制的话,那么我们可以进行拆点,把点的限制转化成边限制。先来一道经典的建图题,只要把这题体会清楚了,那么之后的建图也就会清晰很多。
A - ACM Computer Factory
把工厂拆成2个点,两个点间的容量就为他最大的容量。之后根据他们的关系建图就行了(主要是拆点)。

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int maxv = 55;
const int inf = 0x3f3f3f3f;
struct Edge
{
    int from, to, cap, flow;
    Edge(int u, int v, int c, int f) :from(u), to(v), cap(c), flow(f) {}
    Edge() {}
};
struct Dinic
{
    int n, m, s, t;
    vector<Edge>edges;
    vector<int>G[maxv + 50];
    bool vis[maxv + 50];
    int d[maxv + 50];
    int cur[maxv + 50];

    void AddEdge(int from, int to, int cap)
    {
        edges.push_back(Edge(from, to, cap, 0));
        edges.push_back(Edge(to, from, 0, 0));
        m = edges.size();
        G[from].push_back(m - 2);
        G[to].push_back(m - 1);
    }

    void init(int n)
    {
        for (int i = 0;i <= n;i++)G[i].clear();
        edges.clear();
    }

    bool BFS()
    {
        memset(vis, 0, sizeof(vis));
        queue<int>Q;
        Q.push(s);
        d[s] = 0;
        vis[s] = 1;
        while (!Q.empty())
        {
            int x = Q.front();Q.pop();
            for (int i = 0;i < G[x].size();i++)
            {
                Edge&e = edges[G[x][i]];
                if (!vis[e.to] && e.cap > e.flow)
                {
                    vis[e.to] = 1;
                    d[e.to] = d[x] + 1;
                    Q.push(e.to);
                }
            }
        }
        return vis[t];
    }

    int DFS(int x, int a)
    {
        if (x == t || a == 0)return a;
        int flow = 0, f;
        for (int &i = cur[x];i < G[x].size();i++)
        {
            Edge&e = edges[G[x][i]];
            if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow)))>0)
            {
                e.flow += f;
                edges[G[x][i] ^ 1].flow -= f;
                flow += f;
                a -= f;
                if (a == 0)break;
            }
        }
        return flow;
    }
    int Maxflow(int s, int t)
    {
        //cout << edges.size() << endl;
        this->s = s;this->t = t;
        int flow = 0;
        while (BFS())
        {
            memset(cur, 0, sizeof(cur));
            flow += DFS(s, inf);
        }
        return flow;
    }

}ans;
int w[maxv];
int p[maxv][15];
int P, N;
bool check(int u, int num)
{
    if (num == 0)
    {
        for (int i = 1;i <= P;i++)
            if (p[u][i] == 1)return 0;
        return 1;
    }
    if (num == 1)
    {
        for (int i = P+1;i <= 2*P;i++)if (p[u][i] == 0)return 0;
        return 1;
    }
}

bool check1(int a, int b)
{
    for (int i = 1;i <= P;i++)
    {
        int tmpa = p[a][i + P];
        int tmpb = p[b][i];
        if (tmpa + tmpb == 1)return 0;
    }
    return 1;
}
bool vis[3000];
int main()
{

    scanf("%d %d", &P, &N);
    for (int i = 1;i <= N;i++)
    {
        scanf("%d", &w[i]);
        for (int j = 1;j <= 2*P;j++)
            scanf("%d", &p[i][j]);
    }
    int s = 0, t = 2 * N + 1;
    int n = 2 * N + 1;
    ans.init(n);
    for (int i = 1;i <= N;i++)
        ans.AddEdge(i, i + N, w[i]);
    for (int i = 1;i <= N;i++)
    {
        if (check(i, 0))
            ans.AddEdge(s, i, inf);
        if (check(i, 1))
            ans.AddEdge(i + N, t, inf);
        for (int j = 1;j <= N;j++)if (check1(i, j))
            ans.AddEdge(i + N, j, inf);
    }
    printf("%d ", ans.Maxflow(s, t));
    int routenum = 0;

    for (int i = 0;i < ans.edges.size();i += 2)
    {
        Edge &e = ans.edges[i];
        if (e.flow > 0&&e.from!=s&&e.to!=t&&e.from+N!=e.to)
            vis[i]=1, routenum++;
    }
    printf("%d\n", routenum);
    for (int i = 0;i < ans.edges.size();i += 2)if (vis[i])
    {
        Edge &e = ans.edges[i];
        //cout << i << " ";
        printf("%d %d %d\n", e.from-N, e.to, e.flow);
    }

}

G - Island Transport
这题主要卡dinic,在这里贴一下ispa模板。

#include <iostream>  
#include <stdio.h>  
#include <string.h>  
#include <math.h>  
#include <algorithm>  
using namespace std;  
int head[210000], s, t, nv, maxint=0x3f3f3f3f, cnt;  
int cur[210000], pre[210000], q[5000000], d[210000], num[210000];  
struct node  
{  
    int u, v, cap, next;  
}edge[11000000];  
void add(int u, int v, int cap)  
{  
    edge[cnt].v=v;  
    edge[cnt].cap=cap;  
    edge[cnt].next=head[u];  
    head[u]=cnt++;  

    edge[cnt].v=u;  
    edge[cnt].cap=cap;  
    edge[cnt].next=head[v];  
    head[v]=cnt++;  
}  
void bfs()  
{  
    memset(num,0,sizeof(num));  
    memset(d,-1,sizeof(d));  
    int f1=0, f2=0, i;  
    q[f1++]=t;  
    d[t]=0;  
    num[0]=1;  
    while(f1>=f2)  
    {  
        int u=q[f2++];  
        for(i=head[u];i!=-1;i=edge[i].next)  
        {  
            int v=edge[i].v;  
            if(d[v]==-1)  
            {  
                d[v]=d[u]+1;  
                num[d[v]]++;  
                q[f1++]=v;  
            }  
        }  
    }  
}  
void isap()  
{  
    memcpy(cur,head,sizeof(cur));  
    int flow=0, u=pre[s]=s, i;  
    bfs();  
    while(d[s]<nv)  
    {  
        if(u==t)  
        {  
            int f=maxint, pos;  
            for(i=s;i!=t;i=edge[cur[i]].v)  
            {  
                if(f>edge[cur[i]].cap)  
                {  
                    f=edge[cur[i]].cap;  
                    pos=i;  
                }  
            }  
            for(i=s;i!=t;i=edge[cur[i]].v)  
            {  
                edge[cur[i]].cap-=f;  
                edge[cur[i]^1].cap+=f;  
            }  
            flow+=f;  
            //printf("--");  
            u=pos;  
        }  
        for(i=cur[u];i!=-1;i=edge[i].next)  
        {  
            if(d[edge[i].v]+1==d[u]&&edge[i].cap)  
            {  
                break;  
            }  
        }  
        if(i!=-1)  
        {  
            cur[u]=i;  
            pre[edge[i].v]=u;  
            u=edge[i].v;  
        }  
        else  
        {  
            if(--num[d[u]]==0) break;  
            int mind=nv+1;  
            for(i=head[u];i!=-1;i=edge[i].next)  
            {  
                if(mind>d[edge[i].v]&&edge[i].cap)  
                {  
                    mind=d[edge[i].v];  
                    cur[u]=i;  
                }  
            }  
            d[u]=mind+1;  
            num[d[u]]++;  
            u=pre[u];  
        }  
    }  
    printf("%d\n",flow);  
}  
int read(){  
    int flag = 0, x = 0;  
    char ch = ' ';  
    while(ch != '-' && (ch > '9' || ch < '0')) ch = getchar();  
    if(ch == '-') flag = 1, ch = getchar();  
    while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();  
    return flag ? -x : x;  
}  
int main()  
{  
    int T, n, m, i, j, a, b, c, x, y, min1, max1;  
    scanf("%d",&T);  
    while(T--)  
    {  
        memset(head,-1,sizeof(head));  
        cnt=0;  
        n=read();m=read();  
        min1=999999;  
        max1=-999999;  
        for(i=1;i<=n;i++)  
        {  
            x=read();y=read();  
            if(min1>x)  
            {  
                min1=x;  
                s=i;  
            }  
           if(max1<x)  
           {  
               max1=x;  
               t=i;  
           }  
        }  
        while(m--)  
        {  
            a=read();  
            b=read();  
            c=read();  
            add(a,b,c);  
        }  
        nv=n+1;  
        isap();  
    }  
    return 0;  
}  

I - Control
这题又卡ispa。。。所以用dinic。。(并不知道什么时候用哪个好)

#include <stdio.h>    
#include <string.h>    
#include <algorithm>   
#include<vector>
#include<queue>

using namespace std;
const int maxv = 500;
const int inf = 0x3f3f3f3f;
struct Edge
{
    int from, to, cap, flow;
    Edge(int u, int v, int c, int f) :from(u), to(v), cap(c), flow(f) {}
    Edge() {}
};
struct Dinic
{
    int n, m, s, t;
    vector<Edge>edges;
    vector<int>G[maxv + 50];
    bool vis[maxv + 50];
    int d[maxv + 50];
    int cur[maxv + 50];

    void AddEdge(int from, int to, int cap)
    {
        edges.push_back(Edge(from, to, cap, 0));
        edges.push_back(Edge(to, from, 0, 0));
        m = edges.size();
        G[from].push_back(m - 2);
        G[to].push_back(m - 1);
    }

    void init(int n)
    {
        for (int i = 0;i <= n;i++)G[i].clear();
        edges.clear();
    }

    bool BFS()
    {
        memset(vis, 0, sizeof(vis));
        queue<int>Q;
        Q.push(s);
        d[s] = 0;
        vis[s] = 1;
        while (!Q.empty())
        {
            int x = Q.front();Q.pop();
            for (int i = 0;i < G[x].size();i++)
            {
                Edge&e = edges[G[x][i]];
                if (!vis[e.to] && e.cap > e.flow)
                {
                    vis[e.to] = 1;
                    d[e.to] = d[x] + 1;
                    Q.push(e.to);
                }
            }
        }
        return vis[t];
    }

    int DFS(int x, int a)
    {
        if (x == t || a == 0)return a;
        int flow = 0, f;
        for (int &i = cur[x];i < G[x].size();i++)
        {
            Edge&e = edges[G[x][i]];
            if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow)))>0)
            {
                e.flow += f;
                edges[G[x][i] ^ 1].flow -= f;
                flow += f;
                a -= f;
                if (a == 0)break;
            }
        }
        return flow;
    }
    int Maxflow(int s, int t)
    {
        //cout << edges.size() << endl;
        this->s = s;this->t = t;
        int flow = 0;
        while (BFS())
        {
            memset(cur, 0, sizeof(cur));
            flow += DFS(s, inf);
        }
        return flow;
    }

}ans;

int s, t;
int main() 
{
    int N, M;
    while (~scanf("%d %d",&N,&M))
    {
        ans.init(2 * N + 5);

        int w;
        scanf("%d %d", &s, &t);
        t += N;
        for (int i = 1;i <= N;i++)
            scanf("%d", &w), ans.AddEdge(i, i + N, w);
        int u, v;
        for (int i = 1;i <= M;i++)
        {
            scanf("%d %d", &u, &v);
            ans.AddEdge(u + N, v, inf);
            ans.AddEdge(v + N, u, inf);
        }
        printf("%d\n", ans.Maxflow(s,t));
    }
    return 0;
}

J - Sabotage
最小割模板题,这里复习一下最小割最大流定理:当用cost=最大流把图中的一些边拆掉时,会把图分成两部分。
这里用EdmondsKarp模板,这里面刚好有一个a来记录结点在哪部分。

#include <cstdio>  
#include <cstring>  
#include <algorithm>  
#include <queue>  
#include<iostream>
using namespace std;
const int maxn = 55;
const int inf = 0x3f3f3f3f;

struct Edge
{
    int from, to, cap, flow;
    Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};

struct EdmondsKarp
{
    int n, m;
    vector<Edge>edges;
    vector<int>G[maxn];
    int a[maxn];
    int p[maxn];

    void init(int n)
    {
        for (int i = 0;i <= n;i++)G[i].clear();
        edges.clear();
    }

    void AddEdge(int from, int to, int cap)
    {
        edges.push_back(Edge(from, to, cap, 0));
        edges.push_back(Edge(to, from, cap, 0));
        m = edges.size();
        G[from].push_back(m - 2);
        G[to].push_back(m - 1);
    }

    int Maxflow(int s, int t)
    {
        int flow = 0;
        for (;;)
        {
            memset(a, 0, sizeof(a));
            queue<int>Q;
            Q.push(s);
            a[s] = inf;
            while (!Q.empty())
            {
                int x = Q.front();Q.pop();
                for (int i = 0;i < G[x].size();i++)
                {
                    Edge &e = edges[G[x][i]];
                    if (!a[e.to] && e.cap > e.flow)
                    {
                        p[e.to] = G[x][i];
                        a[e.to] = min(a[x], e.cap - e.flow);
                        Q.push(e.to);
                    }
                }
                if (a[t])break;
            }
            if (!a[t])break;
            for (int u = t;u != s;u = edges[p[u]].from)
            {
                edges[p[u]].flow += a[t];
                edges[p[u] ^ 1].flow -= a[t];
            }
            flow += a[t];
        }
        return flow;
    }
}ans;

int U[505], V[505];
int main()
{
    int n, m;
    int s = 1, t = 2;
    while (~scanf("%d %d", &n, &m) && n)
    {
        ans.init(n);
        int u, v, d;
        for (int i = 1;i <= m;i++)
        {
            scanf("%d %d %d", &u, &v, &d);
            U[i] = u, V[i] = v;
            ans.AddEdge(u, v, d);
        }
        ans.Maxflow(s, t);
        for (int i = 1;i <= m;i++)
        {
            int u = U[i], v = V[i];
            if (ans.a[u] > 0 && ans.a[v] <= 0 || ans.a[u] <= 0 && ans.a[v] > 0)
                printf("%d %d\n", u, v);
        }
        puts("");
    }
    return 0;
}

L - Kakuro Extension
这题比较有意思,建图一开始想到了,但要么re要么wa,搞了好久。。没想到是最后输出的时候弄错了。
建图方式:源点连行,行连白点,白点连列,列连汇点即可。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<vector>
#include<queue>
using namespace std;
const int maxv = 5e5;
const int inf = 0x3f3f3f3f;
struct Edge
{
    int from, to, cap, flow;
    Edge(int u, int v, int c, int f) :from(u), to(v), cap(c), flow(f) {}
    Edge() {}
};
struct Dinic
{
    int n, m, s, t;
    vector<Edge>edges;
    vector<int>G[maxv + 50];
    bool vis[maxv + 50];
    int d[maxv + 50];
    int cur[maxv + 50];

    void AddEdge(int from, int to, int cap)
    {
        edges.push_back(Edge(from, to, cap, 0));
        edges.push_back(Edge(to, from, 0, 0));
        m = edges.size();
        G[from].push_back(m - 2);
        G[to].push_back(m - 1);
    }

    void init(int n)
    {
        for (int i = 0;i <= n;i++)G[i].clear();
        edges.clear();
    }

    bool BFS()
    {
        memset(vis, 0, sizeof(vis));
        queue<int>Q;
        Q.push(s);
        d[s] = 0;
        vis[s] = 1;
        while (!Q.empty())
        {
            int x = Q.front();Q.pop();
            for (int i = 0;i < G[x].size();i++)
            {
                Edge&e = edges[G[x][i]];
                if (!vis[e.to] && e.cap > e.flow)
                {
                    vis[e.to] = 1;
                    d[e.to] = d[x] + 1;
                    Q.push(e.to);
                }
            }
        }
        return vis[t];
    }

    int DFS(int x, int a)
    {
        if (x == t || a == 0)return a;
        int flow = 0, f;
        for (int &i = cur[x];i < G[x].size();i++)
        {
            Edge&e = edges[G[x][i]];
            if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow)))>0)
            {
                e.flow += f;
                edges[G[x][i] ^ 1].flow -= f;
                flow += f;
                a -= f;
                if (a == 0)break;
            }
        }
        return flow;
    }
    int Maxflow(int s, int t)
    {
        //cout << edges.size() << endl;
        this->s = s;this->t = t;
        int flow = 0;
        while (BFS())
        {
            memset(cur, 0, sizeof(cur));
            flow += DFS(s, inf);
        }
        return flow;
    }

}ans;

char map[105][105][10];
int num[105][105][2];
int theid[105][105], ID;
int getnum(int x, int y, int begin)
{
    int thenum = 0;
    for (int i = begin;i < begin + 3;i++)
        thenum = thenum * 10 + map[x][y][i] - '0';
    return thenum;
}
int rows, cows;
int s, t;
int n, m;

int Add(int u,int x, int y, int tp)
{
    if (tp == 0)
    {
        int tmpx = x + 1;
        while (theid[tmpx][y] != 0)
        {
            ans.AddEdge(rows+theid[tmpx][y], u, 8);
            tmpx++;
        }
        return tmpx - x-1;
    }
    if (tp == 1)
    {
        int tmpy = y + 1;
        while (theid[x][tmpy]!=0)
        {
            ans.AddEdge(u, theid[x][tmpy]+rows, 8);
            tmpy++;
        }
        return tmpy - y-1;
    }
}

void buildmap()
{
    s = 0, t = rows + cows + ID + 1;
    ans.init(t);
    int rtmp = 0, ctmp = 0;
    for(int i=1;i<=n;i++)
        for (int j = 1;j <= m;j++)
        {
            if (num[i][j][0])
            {
                ctmp++;
                int use=Add(rows+ID+ctmp,i, j, 0);
                ans.AddEdge(rows + ID + ctmp, t, num[i][j][0]-use);
            }
            if (num[i][j][1])
            {
                rtmp++;
                int use=Add(rtmp, i, j, 1);
                ans.AddEdge(s, rtmp, num[i][j][1]-use);
            }
        }
}
int Ansmap[105][105];
int X[maxv], Y[maxv];
int main()
{

    while (~scanf("%d %d", &n, &m))
    {
        rows = cows = ID=0;
        memset(num, 0, sizeof(num));
        memset(theid, 0, sizeof(theid));
        for (int i = 1;i <= n;i++)
            for (int j = 1;j <= m;j++)
                scanf("%s", map[i][j]);
        int tmp;
        for (int i = 1;i <= n;i++)
            for (int j = 1;j <= m;j++)
            {
                if (map[i][j][0] != 'X'&&map[i][j][0] != '.')
                {
                    cows++;
                    tmp = getnum(i, j, 0);
                    num[i][j][0] = tmp;
                }
                if (map[i][j][4] != 'X'&&map[i][j][4] != '.')
                {
                    rows++;
                    tmp = getnum(i, j, 4);
                    num[i][j][1] = tmp;
                }
                else if (map[i][j][0] == '.')
                    theid[i][j] = ++ID, X[ID] = i, Y[ID] = j;
            }
        buildmap();
        ans.Maxflow(s, t);
        int Size = ans.edges.size();
        for (int i = 0;i < Size;i+=2)
        {
            Edge &e = ans.edges[i];
            if (e.from <= rows&&e.from!=0)
            {
                int to = e.to;
                Ansmap[X[to - rows]][Y[to - rows]] = e.flow;
            }
        }

        for (int i = 1;i <= n;i++)
        {
            for (int j = 1;j <= m;j++)
            {
                if (map[i][j][0] == '.')
                    printf("%d", Ansmap[i][j] + 1);
                else
                    printf("_");
                if (j != m)printf(" ");
            }
            printf("\n");
        }
    }
    return 0;
}

M - Escape
一开始以为这题是个裸题,没想到还是有点技巧在里面。因为n为1e5,所以要么会T,要么会mle。。那么怎么做呢?由于m很少,所以一个人的选择顶多有 210 个状态。所以我们可以把人进行缩点,想清楚这个就和普通的多重匹配没啥区别了。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<vector>
#include<queue>
using namespace std;
const int maxv = 1500;
const int inf = 0x3f3f3f3f;
struct Edge
{
    int from, to, cap, flow;
    Edge(int u, int v, int c, int f) :from(u), to(v), cap(c), flow(f) {}
    Edge() {}
};
struct Dinic
{
    int n, m, s, t;
    vector<Edge>edges;
    vector<int>G[maxv + 50];
    bool vis[maxv + 50];
    int d[maxv + 50];
    int cur[maxv + 50];

    void AddEdge(int from, int to, int cap)
    {
        edges.push_back(Edge(from, to, cap, 0));
        edges.push_back(Edge(to, from, 0, 0));
        m = edges.size();
        G[from].push_back(m - 2);
        G[to].push_back(m - 1);
    }

    void init(int n)
    {
        for (int i = 0;i <= n;i++)G[i].clear();
        edges.clear();
    }

    bool BFS()
    {
        memset(vis, 0, sizeof(vis));
        queue<int>Q;
        Q.push(s);
        d[s] = 0;
        vis[s] = 1;
        while (!Q.empty())
        {
            int x = Q.front();Q.pop();
            for (int i = 0;i < G[x].size();i++)
            {
                Edge&e = edges[G[x][i]];
                if (!vis[e.to] && e.cap > e.flow)
                {
                    vis[e.to] = 1;
                    d[e.to] = d[x] + 1;
                    Q.push(e.to);
                }
            }
        }
        return vis[t];
    }

    int DFS(int x, int a)
    {
        if (x == t || a == 0)return a;
        int flow = 0, f;
        for (int &i = cur[x];i < G[x].size();i++)
        {
            Edge&e = edges[G[x][i]];
            if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow)))>0)
            {
                e.flow += f;
                edges[G[x][i] ^ 1].flow -= f;
                flow += f;
                a -= f;
                if (a == 0)break;
            }
        }
        return flow;
    }
    int Maxflow(int s, int t)
    {
        //cout << edges.size() << endl;
        this->s = s;this->t = t;
        int flow = 0;
        while (BFS())
        {
            memset(cur, 0, sizeof(cur));
            flow += DFS(s, inf);
        }
        return flow;
    }

}ans;
int id[1500];
int tot;
void build(int theid,int a,int c)
{
    int tmp;
    int now = 0;
    while (a)
    {
        tmp = a % 2;
        a /= 2;
        now++;
        if (tmp)
            ans.AddEdge(theid, tot + now, c);
    }
}

int main()
{
    int n, m;
    int s, t;
    while (~scanf("%d %d", &n, &m))
    {
        memset(id, 0, sizeof(id));
        int tmp;
        for (int i = 1;i <= n;i++)
        {
            int num = 0;
            for (int j = 1;j <= m;j++)
            {
                scanf("%d", &tmp);
                num = 2 * num + tmp;
            }
            id[num]++;
        }
        tot = 0;
        for (int i = 0;i < 1500;i++)if (id[i])
            tot++;
        s = 0, t = tot + m + 1;
        ans.init(t);
        tmp = 0;
        for (int i = 0;i < 1500;i++)if(id[i])
        {
            tmp++;
            ans.AddEdge(s, tmp, id[i]);
            build(tmp,i,id[i]);
        }
        for (int i = 1;i <= m;i++)
        {
            scanf("%d", &tmp);
            ans.AddEdge(i + tot, t, tmp);
        }
        tmp = ans.Maxflow(s, t);
        if (tmp == n)puts("YES");
        else puts("NO");
    }
    return 0;
}

N - Marriage Match II
这题如何建图一开始并没有想到。。之后看了题解才恍然大悟。男孩和女孩直接的建图就直接按照题目要求建,然后再给一个源点连向所有女孩,容量为轮数,看最终最大流是否等于轮数*n即可。所以二分轮数就行了。

#include<iostream>
#include<cstring>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int maxv = 250;
const int inf = 0x3f3f3f3f;
struct Edge
{
    int from, to, cap, flow;
    Edge(int u, int v, int c, int f) :from(u), to(v), cap(c), flow(f) {}
    Edge() {}
};
struct Dinic
{
    int n, m, s, t;
    vector<Edge>edges;
    vector<int>G[maxv + 50];
    bool vis[maxv + 50];
    int d[maxv + 50];
    int cur[maxv + 50];

    void AddEdge(int from, int to, int cap)
    {
        edges.push_back(Edge(from, to, cap, 0));
        edges.push_back(Edge(to, from, 0, 0));
        m = edges.size();
        G[from].push_back(m - 2);
        G[to].push_back(m - 1);
    }

    void init(int n)
    {
        for (int i = 0;i <= n;i++)G[i].clear();
        edges.clear();
    }

    bool BFS()
    {
        memset(vis, 0, sizeof(vis));
        queue<int>Q;
        Q.push(s);
        d[s] = 0;
        vis[s] = 1;
        while (!Q.empty())
        {
            int x = Q.front();Q.pop();
            for (int i = 0;i < G[x].size();i++)
            {
                Edge&e = edges[G[x][i]];
                if (!vis[e.to] && e.cap > e.flow)
                {
                    vis[e.to] = 1;
                    d[e.to] = d[x] + 1;
                    Q.push(e.to);
                }
            }
        }
        return vis[t];
    }

    int DFS(int x, int a)
    {
        if (x == t || a == 0)return a;
        int flow = 0, f;
        for (int &i = cur[x];i < G[x].size();i++)
        {
            Edge&e = edges[G[x][i]];
            if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow)))>0)
            {
                e.flow += f;
                edges[G[x][i] ^ 1].flow -= f;
                flow += f;
                a -= f;
                if (a == 0)break;
            }
        }
        return flow;
    }
    int Maxflow(int s, int t)
    {
        //cout << edges.size() << endl;
        this->s = s;this->t = t;
        int flow = 0;
        while (BFS())
        {
            memset(cur, 0, sizeof(cur));
            flow += DFS(s, inf);
        }
        return flow;
    }

}ans;
int s, t;
pair<int, int>pii[10005];
bool map[105][105];
int fa[105];
int find(int a) { return a == fa[a] ? a : fa[a] = find(fa[a]); }
int n, m, f;
bool check(int num)
{
    ans.init(t);
    for (int i = 1;i <= n;i++)
        ans.AddEdge(s, i, num),ans.AddEdge(i+n,t,num);

    for (int i = 1;i <= m;i++)
    {
        int u = pii[i].first, v = pii[i].second;
        ans.AddEdge(u, n + v, 1);
        int fu = find(u);
        for (int j = 1;j <= n;j++)if(j!=u)
        {
            int fj = find(j);
            if (fj == fu&&map[j][v] == 0)
            {
                ans.AddEdge(j, n + v, 1);
            }
        }
    }
    if (ans.Maxflow(s, t) == num*n)return 1;
    return 0;
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        memset(map, 0, sizeof(map));
        scanf("%d %d %d", &n, &m, &f);
        s = 0, t = 2 * n + 1;
        for (int i = 1;i <= n;i++)
            fa[i] = i;
        int u, v;
        for (int i = 1;i <= m;i++)
        {
            scanf("%d %d", &u, &v);
            map[u][v] = 1;
            pii[i] = make_pair(u, v);
        }
        for (int i = 1;i <= f;i++)
        {
            scanf("%d %d", &u, &v);
            int fu = find(u), fv = find(v);
            if (fu != fv)
                fa[fu] = fv;
        }
        int l = 0, r = n, tans = l;
        int mid;
        while (l<=r)
        {
            mid = l + r >> 1;
            if (check(mid))
            {
                tans = mid;
                l = mid + 1;
            }
            else
                r = mid - 1;
        }
        printf("%d\n", tans);
    }

    return 0;
}

O - Marriage Match IV
最后一题之前在最短路出现过,但做的时候并没有想起来,想了一会才知道怎么建图。感觉题挺好的还是贴上来吧。首先我们得求出哪些边在最短路中,然后根据这些边重新建个图,容量为1跑最大流就行了。怎么知道边在最短路中呢,跑两边dijkstra即可。

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 1005;
const int maxm = 100005;
const int maxv = 1005;
const int inf = 0x3f3f3f3f;
struct Edge1
{
    int u, v, dist, next;
    Edge1(int _u,int _v,int _d,int _nxt):u(_u),v(_v),dist(_d),next(_nxt){}
    Edge1(){}
}edges1[maxm], edges2[maxm];

struct HeapNode
{
    int u, d;
    HeapNode(int _u,int _d):u(_u),d(_d){}
    HeapNode(){}
    bool operator<(const HeapNode &b)const
    {
        return d > b.d;
    }
};

int head1[maxn], tot1;
int head2[maxn], tot2;
int n, m;
void addedge(int u, int v, int d,Edge1 *edges, int *head,int &tot)
{
    edges[tot] = Edge1(u, v, d, head[u]);
    head[u] = tot++;
}
int d1[maxn], d2[maxn];
bool vis[maxn];
void dijkstra(int s, int *d, Edge1 *edges, int *head)
{
    for (int i = 1;i <= n;i++)
        d[i] = inf;
    d[s] = 0;
    priority_queue<HeapNode>Q;
    Q.push(HeapNode(s,d[s]));
    memset(vis, 0, sizeof(vis));
    while (!Q.empty())
    {
        HeapNode x = Q.top();Q.pop();
        if (vis[x.u])continue;
        vis[x.u] = 1;
        for (int i = head[x.u];~i;i = edges[i].next)
        {
            Edge1 &e = edges[i];
            if (d[e.v] > d[x.u] + e.dist)
            {
                d[e.v] = d[x.u] + e.dist;
                Q.push(HeapNode(e.v, d[e.v]));
            }
        }
    }
}

struct Edge
{
    int from, to, cap, flow;
    Edge(int u, int v, int c, int f) :from(u), to(v), cap(c), flow(f) {}
    Edge() {}
};
struct Dinic
{
    int n, m, s, t;
    vector<Edge>edges;
    vector<int>G[maxv + 50];
    bool vis[maxv + 50];
    int d[maxv + 50];
    int cur[maxv + 50];

    void AddEdge(int from, int to, int cap)
    {
        edges.push_back(Edge(from, to, cap, 0));
        edges.push_back(Edge(to, from, 0, 0));
        m = edges.size();
        G[from].push_back(m - 2);
        G[to].push_back(m - 1);
    }

    void init(int n)
    {
        for (int i = 0;i <= n;i++)G[i].clear();
        edges.clear();
    }

    bool BFS()
    {
        memset(vis, 0, sizeof(vis));
        queue<int>Q;
        Q.push(s);
        d[s] = 0;
        vis[s] = 1;
        while (!Q.empty())
        {
            int x = Q.front();Q.pop();
            for (int i = 0;i < G[x].size();i++)
            {
                Edge&e = edges[G[x][i]];
                if (!vis[e.to] && e.cap > e.flow)
                {
                    vis[e.to] = 1;
                    d[e.to] = d[x] + 1;
                    Q.push(e.to);
                }
            }
        }
        return vis[t];
    }

    int DFS(int x, int a)
    {
        if (x == t || a == 0)return a;
        int flow = 0, f;
        for (int &i = cur[x];i < G[x].size();i++)
        {
            Edge&e = edges[G[x][i]];
            if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow)))>0)
            {
                e.flow += f;
                edges[G[x][i] ^ 1].flow -= f;
                flow += f;
                a -= f;
                if (a == 0)break;
            }
        }
        return flow;
    }
    int Maxflow(int s, int t)
    {
        //cout << edges.size() << endl;
        this->s = s;this->t = t;
        int flow = 0;
        while (BFS())
        {
            memset(cur, 0, sizeof(cur));
            flow += DFS(s, inf);
        }
        return flow;
    }

}ans;

int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        tot1 = tot2 = 0;
        memset(head1, -1, sizeof(head1));
        memset(head2, -1, sizeof(head1));
        scanf("%d %d", &n, &m);
        int u, v, d;
        for (int i = 1;i <= m;i++)
        {
            scanf("%d %d %d", &u, &v, &d);
            if (u == v)continue;
            addedge(u, v, d, edges1, head1, tot1);
            addedge(v, u, d, edges2, head2, tot2);
        }
        int s, t;
        scanf("%d %d", &s, &t);
        dijkstra(s, d1, edges1, head1);
        dijkstra(t, d2, edges2, head2);
        ans.init(n);
        int minst = d1[t];
        for (int i = 0;i < tot1;i++)
        {
            Edge1 &e = edges1[i];
            if (d1[e.u] + d2[e.v] + e.dist == minst)
                ans.AddEdge(e.u, e.v, 1);
        }
        printf("%d\n", ans.Maxflow(s, t));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 字符串处理 5 1.1 KMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.2 e-KMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.3 Manacher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.4 AC 自动机 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.5 后缀数组 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.5.1 DA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.5.2 DC3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 1.6 后缀自动机 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 1.6.1 基本函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 1.6.2 例题 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 1.7 字符串 hash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 2 数学 25 2.1 素数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.1.1 素数筛选(判断 <MAXN 的数是否素数) . . . . . . . . . . . . . . . . 25 2.1.2 素数筛选(筛选出小于等于 MAXN 的素数) . . . . . . . . . . . . . . . 25 2.1.3 大区间素数筛选(POJ 2689) . . . . . . . . . . . . . . . . . . . . . . . 25 2.2 素数筛选和合数分解 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 2.3 扩展欧几里得算法(求 ax+by=gcd 的解以及逆元) . . . . . . . . . . . . . . . 27 2.4 求逆元 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 2.4.1 扩展欧几里德法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 2.4.2 简洁写法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 2.4.3 利用欧拉函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 2.5 模线性方程组 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 2.6 随机素数测试和大数分解 (POJ 1811) . . . . . . . . . . . . . . . . . . . . . . . 29 2.7 欧拉函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.7.1 分解质因素求欧拉函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.7.2 筛法欧拉函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.7.3 求单个数的欧拉函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.7.4 线性筛(同时得到欧拉函数和素数表) . . . . . . . . . . . . . . . . . . 32 2.8 高斯消元(浮点数) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 2.9 FFT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 2.10 高斯消元法求方程组的解 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 2.10.1 一类开关问题,对 2 取模的 01 方程组 . . . . . . . . . . . . . . . . . . . 37 2.10.2 解同余方程组 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 2.11 整数拆分 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 2.12 求 A B 的约数之和对 MOD 取模 . . . . . . . . . . . . . . . . . . . . . . . . . . 43 2.13 莫比乌斯反演 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 2.13.1 莫比乌斯函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 2.13.2 例题:BZOJ2301 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 2.14 Baby-Step Giant-Step . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 2.15 自适应 simpson 积分 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 2.16 斐波那契数列取模循环节 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 2.17 原根 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 2.18 快速数论变换 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 2.18.1 HDU4656 卷积取模 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 2.19 其它公式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 2.19.1 Polya . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 kuangbin 1 ACM Template of kuangbin 3 数据结构 56 3.1 划分树 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 3.2 RMQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 3.2.1 一维 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 3.2.2 二维 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 3.3 树链剖分 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 3.3.1 点权 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 3.3.2 边权 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 3.4 伸展树(splay tree) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 3.4.1 例题:HDU1890 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 3.4.2 例题:HDU3726 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 3.5 动态树 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 3.5.1 SPOJQTREE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 3.5.2 SPOJQTREE2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 3.5.3 SPOJQTREE4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 3.5.4 SPOJQTREE5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 3.5.5 SPOJQTREE6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 3.5.6 SPOJQTREE7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 3.5.7 HDU4010 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 3.6 主席树 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 3.6.1 查询区间多少个不同的数 . . . . . . . . . . . . . . . . . . . . . . . . . . 95 3.6.2 静态区间第 k 大 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 3.6.3 树上路径点权第 k 大 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 3.6.4 动态第 k 大 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 3.7 Treap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 3.8 KD 树 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 3.8.1 HDU4347 K 近邻 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 3.8.2 CF44G . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 3.8.3 HDU4742 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 3.9 替罪羊树 (ScapeGoat Tree) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 3.9.1 CF455D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 3.10 动态 KD 树 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 3.11 树套树 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 3.11.1 替罪羊树套 splay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 4 图论 130 4.1 最短路 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 4.1.1 Dijkstra 单源最短路 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 4.1.2 Dijkstra 算法 + 堆优化 . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 4.1.3 单源最短路 bellman_ford 算法 . . . . . . . . . . . . . . . . . . . . . . . 131 4.1.4 单源最短路 SPFA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 4.2 最小生成树 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 4.2.1 Prim 算法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 4.2.2 Kruskal 算法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 4.3 次小生成树 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 4.4 有向图的强连通分量 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 4.4.1 Tarjan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 4.4.2 Kosaraju . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 4.5 图的割点、桥和双连通分支的基本概念 . . . . . . . . . . . . . . . . . . . . . . . 138 4.6 割点与桥 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 4.6.1 模板 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 kuangbin 2 ACM Template of kuangbin 4.6.2 调用 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 4.7 边双连通分支 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143 4.8 点双连通分支 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 4.9 最小树形图 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 4.10 二分图匹配 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 4.10.1 邻接矩阵(匈牙利算法) . . . . . . . . . . . . . . . . . . . . . . . . . . 149 4.10.2 邻接表(匈牙利算法) . . . . . . . . . . . . . . . . . . . . . . . . . . . 150 4.10.3 Hopcroft-Karp 算法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 4.11 二分图多重匹配 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152 4.12 二分图最大权匹配(KM 算法) . . . . . . . . . . . . . . . . . . . . . . . . . . 153 4.13 一般图匹配带花树 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 4.14 一般图最大加权匹配 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 4.15 生成树计数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 4.16 最大 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 4.16.1 SAP 邻接矩阵形式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 4.16.2 SAP 邻接矩阵形式 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 4.16.3 ISAP 邻接表形式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 4.16.4 ISAP+bfs 初始化 + 栈优化 . . . . . . . . . . . . . . . . . . . . . . . . . 165 4.16.5 dinic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166 4.16.6 最大判断多解 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 4.17 最小费用最大 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 4.17.1 SPFA 版费用 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 4.17.2 zkw 费用 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170 4.18 2-SAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172 4.18.1 染色法(可以得到字典序最小的解) . . . . . . . . . . . . . . . . . . . . 172 4.18.2 强连通缩点法(拓扑排序只能得到任意解) . . . . . . . . . . . . . . . . 173 4.19 曼哈顿最小生成树 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177 4.20 LCA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 4.20.1 dfs+ST 在线算法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 4.20.2 离线 Tarjan 算法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 4.20.3 LCA 倍增法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184 4.21 欧拉路 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186 4.21.1 有向图 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186 4.21.2 无向图 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188 4.21.3 混合图 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 4.22 树分治 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 4.22.1 点分治 -HDU5016 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 4.22.2 * 点分治 -HDU4918 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 4.22.3 链分治 -HDU5039 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199 5 搜索 205 5.1 Dancing Links . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 5.1.1 精确覆盖 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 5.1.2 可重复覆盖 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207 5.2 八数码 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209 5.2.1 HDU1043 反向搜索 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209 6 动态规划 212 6.1 最长上升子序列 O(nlogn) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212 6.2 背包 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212 6.3 插头 DP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 kuangbin 3 ACM Template of kuangbin 6.3.1 HDU 4285 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 7 计算几何 218 7.1 二维几何 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 7.2 三维几何 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238 7.3 平面最近点对 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242 7.4 三维凸包 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 7.4.1 HDU4273 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 8 其他 249 8.1 高精度 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249 8.2 完全高精度 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250 8.3 strtok 和 sscanf 结合输入 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256 8.4 解决爆栈,手动加栈 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256 8.5 STL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256 8.5.1 优先队列 priority_queue . . . . . . . . . . . . . . . . . . . . . . . . . . . 256 8.5.2 set 和 multiset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257 8.6 输入输出外挂 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258 8.7 莫队算法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258 8.7.1 分块 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259 8.7.2 Manhattan MST 的 dfs 顺序求解 . . . . . . . . . . . . . . . . . . . . . . 260 8.8 VIM 配置 .

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值