zoukankan      html  css  js  c++  java
  • 网络流入门专题(洛谷题单)

    网络流入门到入土(#1)

    最大流:

    裸最大流:

    P1343 地震逃生

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5 + 10;
    //const int maxm = 1e3 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    int m,n,s,t, x, head[50000], num_edge;
    int cur[50000],deep[50000],last[50000],num[50000];
    //cur当前弧优化; last该点的上一条边; num桶 用来GAP优化
    struct Edge{
        int next,to,dis;
    }edge[400000];
    void add_edge(int from,int to,int dis)
    {
        edge[num_edge].to=to;
        edge[num_edge].dis=dis;
        edge[num_edge].next=head[from];
        head[from]=num_edge++;
    }
    //bfs仅用于更新deep
    void bfs(int t)
    {
        queue<int>q;
        for (int i=0; i<=n; i++) cur[i]=head[i];
        for (int i=1; i<=n; i++) deep[i]=n;
        deep[t]=0;
        q.push(t);
        while (!q.empty())
        {
            int now=q.front(); q.pop();
            for (int i=head[now]; i != -1; i=edge[i].next)
            {
                if (deep[edge[i].to]==n && edge[i^1].dis)//i^1是为了找反边
                {
                    deep[edge[i].to] = deep[now]+1;
                    q.push(edge[i].to);
                }
            }
        }
    }
    
    int add_flow(int s,int t)
    {
        int ans=inf,now=t;
        while (now!=s)
        {
            ans=min(ans,edge[last[now]].dis);
            now=edge[last[now]^1].to;
        }
        now=t;
        while (now!=s)
        {
            edge[last[now]].dis-=ans;
            edge[last[now]^1].dis+=ans;
            now=edge[last[now]^1].to;
        }
        return ans;
    }
    int isap(int s,int t)
    {
        int now=s;
        int maxflow = 0;
        bfs(t);//搜出一条增广路
        for (int i=1; i<=n; i++) num[deep[i]]++;
        while (deep[s]<n)
        {
            if (now==t)
            {//如果到达汇点就直接增广,重新回到源点进行下一轮增广
                maxflow+=add_flow(s,t);
                now=s;//回到源点
            }
            bool has_find=0;
            for (int i=cur[now]; i!=-1; i=edge[i].next)
            {
                if (deep[now]==deep[edge[i].to]+1 && edge[i].dis)//找到一条增广路
                {
                    has_find=true;
                    cur[now]=i;//当前弧优化
                    now=edge[i].to;
                    last[edge[i].to]=i;
                    break;
                }
            }
            if (!has_find)//没有找到出边,重新编号
            {
                int minn=n-1;
                for (int i=head[now]; i!=-1; i=edge[i].next)//回头找路径
                    if (edge[i].dis)
                        minn=min(minn,deep[edge[i].to]);
                if ((--num[deep[now]])==0) break;//GAP优化 出现了断层
                num[deep[now]=minn+1]++;
                cur[now]=head[now];
                if (now!=s)
                    now=edge[last[now]^1].to;
            }
        }
        return maxflow;
    }
    int main(){
        num_edge = 0;
        memset(head,-1,sizeof(head));
        scanf("%d%d%d",&n,&m,&x);
        for(int i=0;i<m;i++){
                int u,v,cap;
                scanf("%d%d%d",&u,&v,&cap);
                add_edge(u,v,cap);
                add_edge(v,u,0);
        }
        s = 1, t = n;
        int ans = isap(s,t);
        if (!ans) cout << "Orz Ni Jinan Saint Cow!" << endl;
        else {
            int ans2 = ceil(x*1./ans);
            printf("%d %d\n", ans, ans2);
        }
    
        return 0;
    }
    View Code

    P2740 [USACO4.2]草地排水

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    //const int maxm = 1e3 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    int m,n,s,t, x, head[maxn], num_edge;
    int cur[maxn],deep[maxn],last[maxn],num[maxn];
    int node_num;
    //cur当前弧优化; last该点的上一条边; num桶 用来GAP优化
    struct Edge{
        int next,to,dis;
    }edge[maxn*2];
    
    void add_edge(int from,int to,int dis)
    {
        edge[num_edge].to=to;
        edge[num_edge].dis=dis;
        edge[num_edge].next=head[from];
        head[from]=num_edge++;
    }
    //bfs仅用于更新deep
    void bfs(int t)
    {
        queue<int>q;
        for (int i=0; i<=node_num; i++) cur[i]=head[i];
        for (int i=1; i<=node_num; i++) deep[i]=node_num;
        deep[t]=0;
        q.push(t);
        while (!q.empty())
        {
            int now=q.front(); q.pop();
            for (int i=head[now]; i != -1; i=edge[i].next)
            {
                if (deep[edge[i].to]==node_num && edge[i^1].dis)//i^1是为了找反边
                {
                    deep[edge[i].to] = deep[now]+1;
                    q.push(edge[i].to);
                }
            }
        }
    }
    
    int add_flow(int s,int t)
    {
        int ans=inf,now=t;
        while (now!=s)
        {
            ans=min(ans,edge[last[now]].dis);
            now=edge[last[now]^1].to;
        }
        now=t;
        while (now!=s)
        {
            edge[last[now]].dis-=ans;
            edge[last[now]^1].dis+=ans;
            now=edge[last[now]^1].to;
        }
        return ans;
    }
    int isap(int s,int t)
    {
        int now=s;
        int maxflow = 0;
        bfs(t);//搜出一条增广路
        for (int i=1; i<=node_num; i++) num[deep[i]]++;
        while (deep[s]<node_num)
        {
            if (now==t)
            {//如果到达汇点就直接增广,重新回到源点进行下一轮增广
                maxflow+=add_flow(s,t);
                now=s;//回到源点
            }
            bool has_find=0;
            for (int i=cur[now]; i!=-1; i=edge[i].next)
            {
                if (deep[now]==deep[edge[i].to]+1 && edge[i].dis)//找到一条增广路
                {
                    has_find=true;
                    cur[now]=i;//当前弧优化
                    now=edge[i].to;
                    last[edge[i].to]=i;
                    break;
                }
            }
            if (!has_find)//没有找到出边,重新编号
            {
                int minn=node_num-1;
                for (int i=head[now]; i!=-1; i=edge[i].next)//回头找路径
                    if (edge[i].dis)
                        minn=min(minn,deep[edge[i].to]);
                if ((--num[deep[now]])==0) break;//GAP优化 出现了断层
                num[deep[now]=minn+1]++;
                cur[now]=head[now];
                if (now!=s)
                    now=edge[last[now]^1].to;
            }
        }
        return maxflow;
    }
    int main(){
        num_edge = 0;
        memset(head,-1,sizeof(head));
    
        scanf("%d %d", &n, &m);
        node_num = m;
        s = 1, t = m;
        for (int i = 1, u, v, w; i <= n; ++ i) {
            scanf("%d %d %d", &u, &v, &w);
            add_edge(u, v, w), add_edge(v, u, 0);
        }
    
        int ans = isap(s,t);
        printf("%d\n", ans);
    
        return 0;
    }
    View Code

    SP4063 MPIGS - Sell Pigs

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    
    struct Edge{
        int to;
        int next;
        int w;
    }edge[maxn*2];
    
    int head[maxn];
    int cur[maxn];//当前弧优化数组
    int n, m, S, T;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    int node_num;
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
    }
    
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        for ( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
        for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
        return x * f;
    }
    
    inline void Add_Edge(int u, int v, int w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    
        edge[cnt].next = head[v];
        edge[cnt].to = u;
        edge[cnt].w = 0;
        head[v] = cnt++;
    }
    
    inline bool Bfs(){
        for(int i = 0; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[S] = 0;
        queue<int> q;
        q.push(S);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[T] != -1;
    }
    
    inline int dfs(int u, int flow){
        if(u == T) return flow;
        int del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                int ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline int Dinic(){
        int ans = 0;
        while(Bfs()){
            for(int i = 0; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(S, inf);
        }
        return ans;
    }
    
    int cap[maxn];
    int vis[maxn];
    int main() {
        init();
        scanf("%d %d", &m, &n);
        S = 0, T = n+1;
        node_num = T;
        for (int i = 1; i <= m; ++ i)
            scanf("%d", &cap[i]);
        for (int i = 1; i <= n; ++ i){
            int num; scanf("%d", &num);
            for (int j = 1; j <= num; ++j) {
                int temp; scanf("%d", &temp);
                if (!vis[temp]) vis[temp] = i, Add_Edge(S, i, cap[temp]);
                else Add_Edge(vis[temp], i, inf);
                vis[temp] = i;
            }
            int val; scanf("%d", &val);
            Add_Edge(i, T, val);
        }
        printf("%d\n", Dinic());
        return 0;
    }
    View Code

    点限制最大流(拆点最大流

    P1231 教辅的组成

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    
    struct Edge{
        int to;
        int next;
        int w;
    }edge[maxn*2];
    
    int head[maxn];
    int cur[maxn];//当前弧优化数组
    int n, m, s, t, k;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    int node_num;
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
    }
    
    inline void Add_Edge(int u, int v, int w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    }
    
    inline bool Bfs(){
        for(int i = 1; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[s] = 0;
        queue<int> q;
        q.push(s);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[t] != -1;
    }
    
    inline int dfs(int u, int flow){
        if(u == t) return flow;
        int del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                int ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline int Dinic(){
        int ans = 0;
        while(Bfs()){
            for(int i = 1; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(s, inf);
        }
        return ans;
    }
    
    int main(){
        int cnt = 0;
        memset(head, -1, sizeof(head));
        int n1, n2, n3;
        scanf("%d %d %d", &n1, &n2, &n3); //书,练习册,答案
    
        s = 1, t = n1*2+n2+n3+2;
        node_num = t;
        for (int i = 1; i <= n1; ++ i) {
            int book1 = (i-1)*2+1+1, book2 = book1 + 1;
            Add_Edge(book1, book2, 1), Add_Edge(book2, book1, 0);
            //cout << book1 << "---" << book2 << endl;
        }
        for (int i = 1; i <= n2; ++ i) {
            int v = i + 2*n1+1;
            Add_Edge(s, v, 1), Add_Edge(v, s, 0);
            //cout << s << "---" << v << endl;
        }
        for (int i = 1; i <= n3; ++ i) {
            int v = n1*2+n2+i+1;
            Add_Edge(v, t, 1), Add_Edge(t, v, 0);
            //cout << v << "---" << t << endl;
        }
    
    
        int m1, m2;
        scanf("%d", &m1);
        for (int i = 1, u, v; i <= m1; i++) {
            scanf("%d %d", &u, &v);
            int book1 = (u-1)*2+1+1;
            v = n1*2+1+v;
            Add_Edge(v, book1, 1), Add_Edge(book1, v, 0);
            //cout << v << "---" << book1 << endl;
        }
    
        scanf("%d", &m2);
        for (int i = 1, u, v; i <= m2; i++) {
            scanf("%d %d", &u, &v);
            int book2 = (u-1)*2+1+1+1, an = v+n1*2+n2+1;
            Add_Edge(book2, an, 1), Add_Edge(an, book2, 0);
            //cout << book2 << "---" << an << endl;
        }
        printf("%d\n", Dinic());
        return 0;
    }
    View Code

    P1402 酒店之王

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    
    struct Edge{
        int to;
        int next;
        int w;
    }edge[maxn*2];
    
    int head[maxn];
    int cur[maxn];//当前弧优化数组
    int n, m, s, t, k;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    int node_num;
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
    }
    
    inline void Add_Edge(int u, int v, int w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    }
    
    inline bool Bfs(){
        for(int i = 1; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[s] = 0;
        queue<int> q;
        q.push(s);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[t] != -1;
    }
    
    inline int dfs(int u, int flow){
        if(u == t) return flow;
        int del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                int ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline int Dinic(){
        int ans = 0;
        while(Bfs()){
            for(int i = 1; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(s, inf);
        }
        return ans;
    }
    
    int main(){
        cnt = 0;
        memset(head, -1, sizeof(head));
        int n1, n2, n3;
        scanf("%d %d %d", &n1, &n2, &n3); //书,练习册,答案
    
        s = 1, t = n1*2+n2+n3+2;
        node_num = t;
    
        for (int i = 1; i <= n1; ++ i) {
            int people1 = (i-1)*2+1+1, people2 = people1 + 1;
            Add_Edge(people1, people2, 1), Add_Edge(people2, people1, 0);
        }
        for (int i = 1; i <= n2; ++ i) {
            int v = i + 2*n1+1;
            Add_Edge(s, v, 1), Add_Edge(v, s, 0);
        }
        for (int i = 1; i <= n3; ++ i) {
            int v = n1*2+n2+i+1;
            Add_Edge(v, t, 1), Add_Edge(t, v, 0);
        }
    
    
        for (int i = 1; i <= n1; i++) {
            for (int j = 1, temp; j <= n2; ++ j) {
                scanf("%d", &temp);
                if (!temp) continue;
                int people1 = (i-1)*2+1+1, v = n1*2+1+j;
                Add_Edge(v, people1, 1), Add_Edge(people1, v, 0);
            }
    
        }
    
        for (int i = 1; i <= n1; i++) {
            for (int j = 1, temp; j <= n3; ++ j) {
                scanf("%d", &temp);
                if (!temp) continue;
                int people2 = (i-1)*2+1+1+1, an = j+n1*2+n2+1;
                Add_Edge(people2, an, 1), Add_Edge(an, people2, 0);
            }
        }
        printf("%d\n", Dinic());
        return 0;
    }
    View Code

    P2472 [SCOI2007]蜥蜴

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e7 + 10;
    const int maxm = 1e5 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    
    struct Edge{
        int to;
        int next;
        int w;
    }edge[maxn*2];
    
    int head[maxn];
    int cur[maxn];//当前弧优化数组
    int n, m, s, t, k, r, d;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    int node_num;
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
    }
    
    inline void Add_Edge(int u, int v, int w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    
        edge[cnt].next = head[v];
        edge[cnt].to = u;
        edge[cnt].w = 0;
        head[v] = cnt++;
    }
    
    inline bool Bfs(){
        for(int i = 1; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[s] = 0;
        queue<int> q;
        q.push(s);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[t] != -1;
    }
    
    inline int dfs(int u, int flow){
        if(u == t) return flow;
        int del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                int ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline int Dinic(){
        int ans = 0;
        while(Bfs()){
            for(int i = 1; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(s, inf);
        }
        return ans;
    }
    
    inline int id1(int x, int y) { return (x-1)*m+y; }
    inline int id2(int x, int y) { return (x-1)*m+y+n*m; }
    inline int cal(int x1, int y1, int x2, int y2) { return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2); }
    char g[205][205];
    char gg[205][205];
    int id[205][205];
    char str[30];
    int main() {
        cnt = 0;
        memset(head, -1, sizeof(head));
        scanf("%d%d%d", &n, &m, &d);
        s = 1, t = n*m*2+2;//每个点拆成两个点,表示从石柱顶连向石柱下端
        node_num = t;
        for(int i = 1; i <= n; i ++) {
            scanf("%s", str+1);
            for(int j = 1; j <= m; j ++) if(str[j]-'0' > 0) Add_Edge(id1(i, j)+1, id2(i, j)+1, str[j]-'0');
        }//这个点有石柱,石柱顶连向石柱下端,容量为石柱高
        int res = 0;
        for(int i = 1; i <= n; i ++) {
            scanf("%s", str+1);
            for(int j = 1; j <= m; j ++) if(str[j] == 'L') Add_Edge(s, id1(i, j)+1, 1), res ++;
        }//这个点有蜥蜴,源点连向石柱的上端
        for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= m; j ++)
                if(i-d < 1 || i+d > n || j-d < 1 || j+d > m) Add_Edge(id2(i, j)+1, t, inf);//可以跳出去,石柱的底连向汇点
        for(int x1 = 1; x1 <= n; x1 ++)//距离小于等于d,可以跳到的两个点连边
            for(int y1 = 1; y1 <= m; y1 ++)
                for(int x2 = 1; x2 <= n; x2 ++)
                    for(int y2 = 1; y2 <= m; y2 ++)
                        if(cal(x1, y1, x2, y2) <= d*d) Add_Edge(id2(x1, y1)+1, id1(x2, y2)+1, inf);
    
        printf("%d\n", res-Dinic());
        return 0;
    }
    View Code

    P2763 试题库问题

    这一题的输出方式值得记住;

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    
    struct Edge{
        int to;
        int next;
        int w;
    }edge[maxn*2];
    
    int head[maxn];
    int cur[maxn];//当前弧优化数组
    int n, m, S, T, k, d;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    int node_num;
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
    }
    
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        for ( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
        for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
        return x * f;
    }
    
    inline void Add_Edge(int u, int v, int w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    
        edge[cnt].next = head[v];
        edge[cnt].to = u;
        edge[cnt].w = 0;
        head[v] = cnt++;
    }
    
    inline bool Bfs(){
        for(int i = 0; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[S] = 0;
        queue<int> q;
        q.push(S);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[T] != -1;
    }
    
    inline int dfs(int u, int flow){
        if(u == T) return flow;
        int del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                int ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline int Dinic(){
        int ans = 0;
        while(Bfs()){
            for(int i = 0; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(S, inf);
        }
        return ans;
    }
    
    int main() {
        init();
        n = read(), m = read();
        S = 0, T = n+m+1;
        int sum = 0;
        node_num = T;
        for (int i = 1, w; i <= n; ++ i) {
            scanf("%d", &w);
            Add_Edge(S, i, w);
            sum += w;
        }
        for (int i = 1; i <= m; ++ i) {
            int num;
            scanf("%d", &num);
            Add_Edge(i+n, T, 1);
            for (int j = 1; j <= num; ++ j) {
                int temp;
                scanf("%d", &temp);
                Add_Edge(temp, i+n, 1);
            }
        }
        if (Dinic() != sum)
            cout << "No Solution!" << endl;
        else {
            for (int i = 1; i <= n; ++ i){
                cout << i << ":";
                for (int j = head[i]; ~j; j = edge[j].next)
                    if (edge[j].to > 0 && !edge[j].w)
                      printf(" %d", edge[j].to-n);
                cout << endl;
            }
        }
        return 0;
    }
    View Code

    P2891 [USACO07OPEN]Dining G

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    
    struct Edge{
        int to;
        int next;
        int w;
    }edge[maxn*2];
    
    int head[maxn];
    int cur[maxn];//当前弧优化数组
    int n, m, S, T, f, d;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    int node_num;
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
    }
    
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        for ( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
        for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
        return x * f;
    }
    
    inline void Add_Edge(int u, int v, int w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    
        edge[cnt].next = head[v];
        edge[cnt].to = u;
        edge[cnt].w = 0;
        head[v] = cnt++;
    }
    
    inline bool Bfs(){
        for(int i = 0; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[S] = 0;
        queue<int> q;
        q.push(S);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[T] != -1;
    }
    
    inline int dfs(int u, int flow){
        if(u == T) return flow;
        int del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                int ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline int Dinic(){
        int ans = 0;
        while(Bfs()){
            for(int i = 0; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(S, inf);
        }
        return ans;
    }
    
    int main() {
        init();
        scanf("%d %d %d", &n, &f, &d);
        S = 0, T = f+d+2*n+1;
        node_num = T;
        int sum = 0;
        for (int i = 1; i <= f; ++i)
            Add_Edge(S, i+n*2, 1);
        for (int i = 1; i <= d; ++i)
            Add_Edge(i+f+n*2, T, 1);
        for (int i = 1; i <= n; ++ i) {
            int fi, di;
            Add_Edge((i-1)*2+1, (i-1)*2+2, 1);
            scanf("%d %d", &fi, &di);
            for (int j = 1, tf; j <= fi; ++ j) {
                scanf("%d", &tf);
                Add_Edge(tf+n*2, (i-1)*2+1, 1);
            }
            for (int j = 1, td; j <= di; ++ j) {
                scanf("%d", &td);
                Add_Edge((i-1)*2+2, td+f+n*2, 1);
            }
        }
        printf("%d\n", Dinic());
        return 0;
    }
    View Code

    P3254 圆桌问题

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    #define pii pair<long long, int>
    typedef long long ll;
    
    const int maxn = 1e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const ll inf = 1e18;
    const int mod = 1e9 + 7;
    
    
    struct Edge{
        int to;
        int next;
        ll w;
    } edge[maxn*2];
    
    int head[maxn], node_num;
    int cur[maxn];//当前弧优化数组
    int n, m, S, T, k;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    bool vis[maxn];
    
    inline void init(){
        cnt = 0;
        for (int i = 0; i <= node_num; ++ i) head[i] = -1;
    }
    
    inline void Add_Edge(int u, int v, ll w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    
        edge[cnt].next = head[v];
        edge[cnt].to = u;
        edge[cnt].w = 0;
        head[v] = cnt++;
    }
    
    
    inline bool Bfs(){
        for(int i = 0; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[S] = 0;
        queue<int> q;
        q.push(S);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[T] != -1;
    }
    
    inline ll dfs(int u, ll flow){
        if(u == T) return flow;
        ll del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                ll ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline ll Dinic() {
        ll ans = 0;
        while(Bfs()) {
            for(int i = 0; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(S, inf);
        }
        return ans;
    }
    
    int main() {
        scanf("%d %d", &m, &n);
        S = 0, T = n+m+1;
        node_num = T;
        init();
        int rec_n[n+1], rec_m[m+1];
        int sum = 0;
        for (int i = 1; i <= m; ++ i) {
            scanf("%d", &rec_m[i]);
            sum += rec_m[i];
            Add_Edge(S, i, rec_m[i]);
            for (int j = 1; j <= n; ++ j)
                Add_Edge(i, j+m, 1);
        }
        for (int i = 1; i <= n; ++ i) {
            scanf("%d", &rec_n[i]);
            Add_Edge(i+m, T, rec_n[i]);
        }
        int flag = 0;
        if (Dinic() == sum) flag = 1;
        cout << flag << endl;
        if (flag) {
            vector<int> rec[m+1];
            for (int u = 1; u <= m; ++ u) {
                for (int j = head[u]; ~j; j = edge[j].next) {
                    if (edge[j].w == 0) {
                        rec[u].push_back(edge[j].to-m);
                    }
                }
            }
            for (int i = 1; i <= m; ++ i) {
                cout << rec[i][0];
                for (int j = 1; j < rec[i].size(); ++ j)
                    cout << " " << rec[i][j];
                cout << endl;
            }
        }
        return 0;
    }
    View Code

    最小割:

    裸最小割:

    P3931 SAC E#1 - 一道难题 Tree

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    
    struct Edge{
        int to;
        int next;
        int w;
    }edge[maxn*2];
    
    int head[maxn];
    int cur[maxn];//当前弧优化数组
    int n, m, s, t, x;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    int node_num;
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
    }
    
    inline void Add_Edge(int u, int v, int w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    }
    
    inline bool Bfs(){
        for(int i = 1; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[s] = 0;
        queue<int> q;
        q.push(s);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[t] != -1;
    }
    
    inline int dfs(int u, int flow){
        if(u == t) return flow;
        int del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                int ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline int Dinic(){
        int ans = 0;
        while(Bfs()){
            for(int i = 1; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(s, inf);
        }
        return ans;
    }
    
    map<pair<int, int>, int> wei;
    vector<int> G[maxn];
    int vis[maxn];
    void DFS(int st)
    {
        vis[st] = 1;
        for (int i=0; i < G[st].size(); ++ i) {
            int v = G[st][i];
            if (vis[v]) continue;
            Add_Edge(st, v, wei[{st, v}]), Add_Edge(v, st, 0);
            //cout << st << " ---- " << v << "  " << wei[{st, v}] << endl;
            if (G[v].size() == 1) {
                //cout << v << " ---- " << t << endl;
                Add_Edge(v, t, inf), Add_Edge(t, v, 0);
            }
            else
                DFS(v);
        }
    }
    
    int main(){
        init();
        int root;
        scanf("%d %d", &n, &root);
        s = 1, t = n+2;
        node_num = n+2;
        Add_Edge(s, root+1, inf), Add_Edge(root+1, s, 0);
        for (int i = 1; i <= n-1; i++) {
            int u, v, w;
            scanf("%d %d %d", &u, &v, &w);
            u ++, v ++;
            wei[{u, v}] = w, wei[{v, u}] = w;
            G[u].push_back(v), G[v].push_back(u);
        }
        DFS(root+1);
        printf("%d\n", Dinic());
        return 0;
    }
    View Code

    P2057 [SHOI2007]善意的投票 / [JLOI2010]冠军调查

    这道题建双向边这里挺耐人寻味的。

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    
    struct Edge{
        int to;
        int next;
        int w;
    }edge[maxn*2];
    
    int head[maxn];
    int cur[maxn];//当前弧优化数组
    int n, m, s, t, k;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    int node_num;
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
    }
    
    inline void Add_Edge(int u, int v, int w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    }
    
    inline bool Bfs(){
        for(int i = 1; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[s] = 0;
        queue<int> q;
        q.push(s);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[t] != -1;
    }
    
    inline int dfs(int u, int flow){
        if(u == t) return flow;
        int del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                int ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline int Dinic(){
        int ans = 0;
        while(Bfs()){
            for(int i = 1; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(s, inf);
        }
        return ans;
    }
    
    int main(){
        cnt = 0;
        memset(head, -1, sizeof(head));
    
        scanf("%d %d", &n, &m); //书,练习册,答案
        s = 1, t = n+2;
        node_num = t;
    
        for (int i = 1,temp; i <= n; ++ i) {
            scanf("%d", &temp);
            if (temp) Add_Edge(s, i+1, 1), Add_Edge(i+1, s, 0);
            else Add_Edge(i+1, t, 1), Add_Edge(t, i+1, 0);
        }
    
    
        for (int i = 1, u, v; i <= m; i++) {
            scanf("%d %d", &u, &v);
            Add_Edge(u+1, v+1, 1), Add_Edge(v+1, u+1, 1), Add_Edge(u+1, v+1, 0), Add_Edge(v+1, u+1, 0);
        }
        printf("%d\n", Dinic());
        return 0;
    }
    View Code

    P1344 [USACO4.4]追查坏牛奶Pollutant Control

    这题有一个如何统计割边数的小技巧:

    就是给边权加上一个大数+1之后再模这个大数,剩下的就是割边数了

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll maxn = 1e6 + 10;
    const ll maxm = 1e5 * 2 + 10;
    const ll inf = 0x3f3f3f3f;
    const ll mod = 1e9 + 7;
    
    struct Edge{
        ll to;
        ll next;
        ll w;
    }edge[maxn*2];
    
    ll head[maxn];
    ll cur[maxn];//当前弧优化数组
    ll n, m, s, t, k;//点数,边数,源点,汇点
    ll dis[maxn];//Bfs深度
    ll cnt = 0;//边数
    ll node_num;
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
    }
    
    inline void Add_Edge(ll u, ll v, ll w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    }
    
    inline bool Bfs(){
        for(ll i = 1; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[s] = 0;
        queue<ll> q;
        q.push(s);
        while(!q.empty()){
            ll u = q.front(); q.pop();
            for(ll i = head[u]; i != -1; i = edge[i].next){
                ll v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[t] != -1;
    }
    
    inline ll dfs(ll u, ll flow){
        if(u == t) return flow;
        ll del = flow;
        for(ll i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            ll v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                ll ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline ll Dinic(){
        ll ans = 0;
        while(Bfs()){
            for(ll i = 1; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(s, inf);
        }
        return ans;
    }
    
    int main(){
        ll cnt = 0;
        memset(head, -1, sizeof(head));
    
        scanf("%lld %lld", &n, &m);
    
        s = 1, t = n;
        node_num = t;
        for (ll i = 1, u, v, w; i <= m; ++ i) {
            scanf("%lld %lld %lld", &u, &v, &w);
            w = w * 1050 + 1;
            Add_Edge(u, v, w), Add_Edge(v, u, 0);
        }
        ll temp = Dinic();
        printf("%lld %lld\n", temp/1050, temp % 1050);
        return 0;
    }
    View Code

    P2944 [USACO09MAR]Earthquake Damage 2 G

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    
    struct Edge{
        int to;
        int next;
        int w;
    }edge[maxn*2];
    
    int head[maxn];
    int cur[maxn];//当前弧优化数组
    int n, m, S, T, p;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    int node_num;
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
    }
    
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        for ( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
        for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
        return x * f;
    }
    
    inline void Add_Edge(int u, int v, int w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    
        edge[cnt].next = head[v];
        edge[cnt].to = u;
        edge[cnt].w = 0;
        head[v] = cnt++;
    }
    
    bool Bfs(){
        for(int i = 0; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[S] = 0;
        queue<int> q;
        q.push(S);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[T] != -1;
    }
    
    int dfs(int u, int flow){
        if(u == T) return flow;
        int del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                int ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline int Dinic(){
        int ans = 0;
        while(Bfs()){
            for(int i = 0; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(S, inf);
        }
        return ans;
    }
    
    int main() {
        init();
        scanf("%d %d %d", &n, &m, &p);
        S = 1, T = 2*n+1;
        node_num = T;
        Add_Edge(S, S+1, inf);
        for (int i = 1, u, v; i <= m; ++ i) {
            scanf("%d %d", &u, &v);
            Add_Edge(u*2, v*2-1, inf);
            Add_Edge(v*2, u*2-1, inf);
        }
        int rec[n+1] = {0};
        for (int i = 1, pi; i <= p; ++ i) {
            scanf("%d", &pi);
            Add_Edge(pi*2-1, pi*2, inf);
            Add_Edge(pi*2, T, inf);
            rec[pi] = 1;
        }
        for (int i = 2; i <= n; ++ i) {
            if (!rec[i]) Add_Edge(i*2-1, i*2, 1);
        }
        printf("%d\n", Dinic());
        return 0;
    }
    View Code

    P3163 [CQOI2014]危桥

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    
    struct Edge{
        int to;
        int next;
        int w;
    }edge[maxn*2];
    
    int head[maxn];
    int cur[maxn];//当前弧优化数组
    int n, m, S, T, k;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    int node_num;
    int rec[100+5][100+5];
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
    }
    
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        for ( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
        for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
        return x * f;
    }
    
    inline void Add_Edge(int u, int v, int w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    
        edge[cnt].next = head[v];
        edge[cnt].to = u;
        edge[cnt].w = 0;
        head[v] = cnt++;
    }
    
    inline bool Bfs(){
        for(int i = 0; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[S] = 0;
        queue<int> q;
        q.push(S);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[T] != -1;
    }
    
    inline int dfs(int u, int flow){
        if(u == T) return flow;
        int del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                int ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline int Dinic(){
        int ans = 0;
        while(Bfs()){
            for(int i = 0; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(S, inf);
        }
        return ans;
    }
    
    bool judge(int mid) {
        init();
        for (int i = 1; i <= n; ++ i) {
            Add_Edge(S, i, mid);
            Add_Edge(i, i+n, k);
            for (int j = 1; j <= n; ++j) {
                if (rec[i][j]) Add_Edge(i, j+2*n, 1);
                else Add_Edge(i+n, j+3*n, 1);
            }
        }
        for (int i = 1; i <= n; ++ i) {
            Add_Edge(i+3*n,i+2*n, k);
            Add_Edge(i+2*n, T, mid);
        }
        return Dinic() == mid * n;
    }
    char g[105][105];
    int main() {
    
        int a1, a2, an, b1, b2, bn;
        while (~scanf("%d %d %d %d %d %d %d %d", &n, &a1, &a2, &an, &b1, &b2, &bn)) {
            init();
            ++ a1, ++ a2, ++ b1, ++ b2;
            S = 0, T = n+1;
            node_num = T;
            Add_Edge(S, a1, inf), Add_Edge(S, b1, inf);
            Add_Edge(a2, T, inf), Add_Edge(b2, T, inf);
            for (int i = 1; i <= n; ++ i) {
                for (int j = 1; j <= n; ++ j) {
                    cin >> g[i][j];
                    if (g[i][j] == 'X') continue;
                    else if(g[i][j] == 'O') Add_Edge(i, j, 2);
                    else Add_Edge(i, j, inf);
                }
            }
            int flag = 0;
            if (Dinic() >= 2*(an+bn)) flag = 1;
            if (flag) {
                init();
                Add_Edge(S, a1, inf), Add_Edge(S, b2, inf);
                Add_Edge(a2, T, inf), Add_Edge(b1, T, inf);
                for (int i = 1; i <= n; ++ i) {
                    for (int j = 1; j <= n; ++ j) {
                        if (g[i][j] == 'X') continue;
                        else if(g[i][j] == 'O') Add_Edge(i, j, 2);
                        else Add_Edge(i, j, inf);
                    }
                }
                if (Dinic() >= 2*(an+bn))
                    cout << "Yes" << endl;
                else cout << "No" << endl;
            }
            else cout << "No" << endl;
        }
        return 0;
    }
    View Code

    P3866 [TJOI2009]战争游戏

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    #define pii pair<long long, int>
    typedef long long ll;
    
    const int maxn = 1e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const ll inf = 1e18;
    const int mod = 1e9 + 7;
    
    
    struct Edge{
        int to;
        int next;
        ll w;
    } edge[maxn*2];
    
    int head[maxn], node_num;
    int cur[maxn];//当前弧优化数组
    int n, m, S, T, k;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    bool vis[maxn];
    
    inline void init(){
        cnt = 0;
        for (int i = 0; i <= node_num; ++ i) head[i] = -1;
    }
    
    inline void Add_Edge(int u, int v, ll w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    
        edge[cnt].next = head[v];
        edge[cnt].to = u;
        edge[cnt].w = 0;
        head[v] = cnt++;
    }
    
    
    inline bool Bfs(){
        for(int i = 0; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[S] = 0;
        queue<int> q;
        q.push(S);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[T] != -1;
    }
    
    inline ll dfs(int u, ll flow){
        if(u == T) return flow;
        ll del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                ll ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline ll Dinic() {
        ll ans = 0;
        while(Bfs()) {
            for(int i = 0; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(S, inf);
        }
        return ans;
    }
    
    int dic[4][2] = {1,0, -1,0, 0,-1, 0,1};
    
    int main() {
        scanf("%d %d", &n, &m);
        S = 0, T = 2*n*m+1;
        node_num = T;
        init();
        int sum = 0;
        int g[n+1][m+1];
        for (int i = 1; i <= n; ++ i) {
           for (int j = 1; j <= m; ++ j) {
                scanf("%d", &g[i][j]);
                int id = (i-1)*m+j, id1 = id+n*m;
                if (g[i][j] > 0)
                    Add_Edge(id, id1, g[i][j]);
                else if (g[i][j] == 0)
                    Add_Edge(S, id, inf), Add_Edge(id, id1, inf);
           }
        }
    
        for (int i = 1; i <= n; ++ i) {
           for (int j = 1; j <= m; ++ j) {
                if (g[i][j] == -1) continue;
                for (int k = 0; k < 4; ++ k) {
                    int tx = i + dic[k][0], ty = j + dic[k][1];
                    int id = (i-1)*m+j, id1 = id+n*m;
                    int td = (tx-1)*m+ty, td1 = (tx-1)*m+ty+n*m;
                    if (tx < 1 || ty < 1 || tx > n || ty > m) {
                        Add_Edge(id1, T, inf);
                        continue;
                    }
                    if (g[tx][ty] == -1) continue;
                    Add_Edge(id1, td, inf);
                }
           }
        }
        cout << Dinic() << endl;
        return 0;
    }
    View Code

    P4001 [ICPC-Beijing 2006]狼抓兔子

    这题是我用ISAP卡过去的,正解应该是对偶图最短路等于最小割

    UPD20.09.23: 已在对偶图专题更新。

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e7 + 10;
    //const int maxm = 1e3 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    int m,n,S,T,k, x, head[maxn], num_edge;
    int cur[maxn],deep[maxn],last[maxn],num[maxn];
    int node_num;
    int cap[40];
    int wanted[maxn][40];
    //cur当前弧优化; last该点的上一条边; num桶 用来GAP优化
    struct Edge{
        int next,to,dis;
    }edge[maxn*2];
    
    void add_edge(int from,int to,int dis)
    {
        edge[num_edge].to=to;
        edge[num_edge].dis=dis;
        edge[num_edge].next=head[from];
        head[from]=num_edge++;
    //
    //    edge[num_edge].to=from;
    //    edge[num_edge].dis=0;
    //    edge[num_edge].next=head[to];
    //    head[to]=num_edge++;
    }
    //bfs仅用于更新deep
    void bfs(int T)
    {
        queue<int>q;
        for (int i=0; i<=node_num; i++) cur[i]=head[i];
        for (int i=0; i<=node_num; i++) deep[i]=node_num;
        deep[T]=0;
        q.push(T);
        while (!q.empty())
        {
            int now=q.front(); q.pop();
            for (int i=head[now]; i != -1; i=edge[i].next)
            {
                if (deep[edge[i].to]==node_num && edge[i^1].dis)//i^1是为了找反边
                {
                    deep[edge[i].to] = deep[now]+1;
                    q.push(edge[i].to);
                }
            }
        }
    }
    
    int add_flow(int S,int T)
    {
        int ans=inf,now=T;
        while (now!=S)
        {
            ans=min(ans,edge[last[now]].dis);
            now=edge[last[now]^1].to;
        }
        now=T;
        while (now!=S)
        {
            edge[last[now]].dis-=ans;
            edge[last[now]^1].dis+=ans;
            now=edge[last[now]^1].to;
        }
        return ans;
    }
    
    int isap()
    {
        int now=S;
        int maxflow = 0;
        bfs(T);//搜出一条增广路
        for (int i=1; i<=node_num; i++) num[deep[i]]++;
        while (deep[S]<node_num)
        {
            if (now==T)
            {//如果到达汇点就直接增广,重新回到源点进行下一轮增广
                maxflow+=add_flow(S,T);
                now=S;//回到源点
            }
            bool has_find=0;
            for (int i=cur[now]; i!=-1; i=edge[i].next)
            {
                if (deep[now]==deep[edge[i].to]+1 && edge[i].dis)//找到一条增广路
                {
                    has_find=true;
                    cur[now]=i;//当前弧优化
                    now=edge[i].to;
                    last[edge[i].to]=i;
                    break;
                }
            }
            if (!has_find)//没有找到出边,重新编号
            {
                int minn=node_num-1;
                for (int i=head[now]; i!=-1; i=edge[i].next)//回头找路径
                    if (edge[i].dis)
                        minn=min(minn,deep[edge[i].to]);
                if ((--num[deep[now]])==0) break;//GAP优化 出现了断层
                num[deep[now]=minn+1]++;
                cur[now]=head[now];
                if (now!=S)
                    now=edge[last[now]^1].to;
            }
        }
        return maxflow;
    }
    
    void init()
    {
        num_edge = 0;
        memset(head,-1,sizeof(head));
    }
    
    inline int read()
    {
        int x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    
    int main() {
        n = read(), m = read();
        init();
        S = 1, T = n*m;
        node_num = T;
        for (int i = 1; i <= n; ++ i) {
            int w;
            for (int j = 2; j <= m; ++ j) {
                w = read();
                int id1 = (i-1)*m+j-1, id2 = (i-1)*m+j;
                add_edge(id1, id2, w);
                add_edge(id2, id1, w);
            }
        }
    
        for (int i = 2; i <= n; ++ i) {
            int w;
            for (int j = 1; j <= m; ++ j) {
                w = read();
                int id1 = (i-2)*m+j, id2 = (i-1)*m+j;
                add_edge(id1, id2, w);
                add_edge(id2, id1, w);
            }
        }
    
        for (int i = 2; i <= n; ++ i) {
            int w;
            for (int j = 2; j <= m; ++ j) {
                w = read();
                int id1 = (i-2)*m+j-1, id2 = (i-1)*m+j;
                add_edge(id1, id2, w);
                add_edge(id2, id1, w);
            }
        }
        cout << isap() << endl;
        return 0;
    }
    View Code

    割点转割边:

    P1345 [USACO5.4]奶牛的电信T

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5 + 10;
    //const int maxm = 1e3 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    int m,n,s,t, x, head[maxn], num_edge;
    int cur[maxn],deep[maxn],last[maxn],num[maxn];
    int node_num;
    //cur当前弧优化; last该点的上一条边; num桶 用来GAP优化
    struct Edge{
        int next,to,dis;
    }edge[maxn*2];
    
    void add_edge(int from,int to,int dis)
    {
        edge[num_edge].to=to;
        edge[num_edge].dis=dis;
        edge[num_edge].next=head[from];
        head[from]=num_edge++;
    }
    //bfs仅用于更新deep
    void bfs(int t)
    {
        queue<int>q;
        for (int i=0; i<=node_num; i++) cur[i]=head[i];
        for (int i=1; i<=node_num; i++) deep[i]=node_num;
        deep[t]=0;
        q.push(t);
        while (!q.empty())
        {
            int now=q.front(); q.pop();
            for (int i=head[now]; i != -1; i=edge[i].next)
            {
                if (deep[edge[i].to]==node_num && edge[i^1].dis)//i^1是为了找反边
                {
                    deep[edge[i].to] = deep[now]+1;
                    q.push(edge[i].to);
                }
            }
        }
    }
    
    int add_flow(int s,int t)
    {
        int ans=inf,now=t;
        while (now!=s)
        {
            ans=min(ans,edge[last[now]].dis);
            now=edge[last[now]^1].to;
        }
        now=t;
        while (now!=s)
        {
            edge[last[now]].dis-=ans;
            edge[last[now]^1].dis+=ans;
            now=edge[last[now]^1].to;
        }
        return ans;
    }
    int isap(int s,int t)
    {
        int now=s;
        int maxflow = 0;
        bfs(t);//搜出一条增广路
        for (int i=1; i<=node_num; i++) num[deep[i]]++;
        while (deep[s]<node_num)
        {
            if (now==t)
            {//如果到达汇点就直接增广,重新回到源点进行下一轮增广
                maxflow+=add_flow(s,t);
                now=s;//回到源点
            }
            bool has_find=0;
            for (int i=cur[now]; i!=-1; i=edge[i].next)
            {
                if (deep[now]==deep[edge[i].to]+1 && edge[i].dis)//找到一条增广路
                {
                    has_find=true;
                    cur[now]=i;//当前弧优化
                    now=edge[i].to;
                    last[edge[i].to]=i;
                    break;
                }
            }
            if (!has_find)//没有找到出边,重新编号
            {
                int minn=node_num-1;
                for (int i=head[now]; i!=-1; i=edge[i].next)//回头找路径
                    if (edge[i].dis)
                        minn=min(minn,deep[edge[i].to]);
                if ((--num[deep[now]])==0) break;//GAP优化 出现了断层
                num[deep[now]=minn+1]++;
                cur[now]=head[now];
                if (now!=s)
                    now=edge[last[now]^1].to;
            }
        }
        return maxflow;
    }
    int main(){
        num_edge = 0;
        memset(head,-1,sizeof(head));
        scanf("%d%d%d%d",&n,&m,&s,&t);
        node_num = 2*n;
        for (int i = 1; i <= n; ++ i)
            add_edge(i,i+n,1), add_edge(i+n,i,0);
    
        for(int i=0;i<m;i++){
            int u,v,cap;
            scanf("%d%d",&u,&v);
            add_edge(u+n,v,inf), add_edge(v,u+n,0);
            add_edge(v+n,u,inf), add_edge(u,v+n,0);
        }
    
        int ans = isap(s+n,t);
        printf("%d\n", ans);
    
        return 0;
    }
    View Code

     

    最大权闭合子图:

    P1361 小M的作物

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    //const int maxm = 1e3 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    int m,n,s,t, x, head[maxn], num_edge;
    int cur[maxn],deep[maxn],last[maxn],num[maxn];
    int node_num;
    //cur当前弧优化; last该点的上一条边; num桶 用来GAP优化
    struct Edge{
        int next,to,dis;
    }edge[maxn*2];
    
    void add_edge(int from,int to,int dis)
    {
        edge[num_edge].to=to;
        edge[num_edge].dis=dis;
        edge[num_edge].next=head[from];
        head[from]=num_edge++;
    }
    //bfs仅用于更新deep
    void bfs(int t)
    {
        queue<int>q;
        for (int i=0; i<=node_num; i++) cur[i]=head[i];
        for (int i=1; i<=node_num; i++) deep[i]=node_num;
        deep[t]=0;
        q.push(t);
        while (!q.empty())
        {
            int now=q.front(); q.pop();
            for (int i=head[now]; i != -1; i=edge[i].next)
            {
                if (deep[edge[i].to]==node_num && edge[i^1].dis)//i^1是为了找反边
                {
                    deep[edge[i].to] = deep[now]+1;
                    q.push(edge[i].to);
                }
            }
        }
    }
    
    int add_flow(int s,int t)
    {
        int ans=inf,now=t;
        while (now!=s)
        {
            ans=min(ans,edge[last[now]].dis);
            now=edge[last[now]^1].to;
        }
        now=t;
        while (now!=s)
        {
            edge[last[now]].dis-=ans;
            edge[last[now]^1].dis+=ans;
            now=edge[last[now]^1].to;
        }
        return ans;
    }
    int isap(int s,int t)
    {
        int now=s;
        int maxflow = 0;
        bfs(t);//搜出一条增广路
        for (int i=1; i<=node_num; i++) num[deep[i]]++;
        while (deep[s]<node_num)
        {
            if (now==t)
            {//如果到达汇点就直接增广,重新回到源点进行下一轮增广
                maxflow+=add_flow(s,t);
                now=s;//回到源点
            }
            bool has_find=0;
            for (int i=cur[now]; i!=-1; i=edge[i].next)
            {
                if (deep[now]==deep[edge[i].to]+1 && edge[i].dis)//找到一条增广路
                {
                    has_find=true;
                    cur[now]=i;//当前弧优化
                    now=edge[i].to;
                    last[edge[i].to]=i;
                    break;
                }
            }
            if (!has_find)//没有找到出边,重新编号
            {
                int minn=node_num-1;
                for (int i=head[now]; i!=-1; i=edge[i].next)//回头找路径
                    if (edge[i].dis)
                        minn=min(minn,deep[edge[i].to]);
                if ((--num[deep[now]])==0) break;//GAP优化 出现了断层
                num[deep[now]=minn+1]++;
                cur[now]=head[now];
                if (now!=s)
                    now=edge[last[now]^1].to;
            }
        }
        return maxflow;
    }
    int main(){
        num_edge = 0;
        memset(head,-1,sizeof(head));
        scanf("%d",&n);
        int cap1[n+2], cap2[n+2];
        int sum = 0;
        for (int i = 2; i < n+2; i++) scanf("%d", &cap1[i]), sum += cap1[i];
        for (int i = 2; i < n+2; i++) scanf("%d", &cap2[i]), sum += cap2[i];
        scanf("%d", &m);
        for (int i = 2; i < n+2; ++ i) {
            add_edge(1, i, cap1[i]), add_edge(i, 1, 0);
            add_edge(i, n+2*m+2, cap2[i]), add_edge(n+2*m+2, i, 0);
        }
        node_num = n+2*m+2;
        s = 1, t = n+2*m+2;
        for (int i = 1, ki, c1, c2; i <= m; ++ i) {
            scanf("%d%d%d", &ki, &c1, &c2);
            sum += c1 + c2;
            int add1 = (n+1)+(i-1)*2+1, add2 = (n+1)+(i-1)*2+2;
            add_edge(s, add1, c1), add_edge(add1, s, 0);
            add_edge(add2, t, c2), add_edge(t, add2, 0);
            for (int j = 1, tp; j <= ki; ++ j) {
                scanf("%d", &tp); tp += 1;
                add_edge(add1, tp, inf), add_edge(tp, add1, 0);
                add_edge(tp, add2, inf), add_edge(add2, tp, 0);
            }
        }
    
        int ans = sum - isap(s,t);
        printf("%d\n", ans);
    
        return 0;
    }
    View Code

    P2762 太空飞行计划问题

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    
    struct Edge{
        int to;
        int next;
        int w;
    }edge[maxn*2];
    
    int head[maxn];
    int cur[maxn];//当前弧优化数组
    int n, m, S, T, k, d;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    int node_num;
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
    }
    
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        for ( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
        for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
        return x * f;
    }
    
    inline void Add_Edge(int u, int v, int w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    
        edge[cnt].next = head[v];
        edge[cnt].to = u;
        edge[cnt].w = 0;
        head[v] = cnt++;
    }
    
    inline bool Bfs(){
        for(int i = 0; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[S] = 0;
        queue<int> q;
        q.push(S);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[T] != -1;
    }
    
    inline int dfs(int u, int flow){
        if(u == T) return flow;
        int del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                int ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline int Dinic(){
        int ans = 0;
        while(Bfs()){
            for(int i = 0; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(S, inf);
        }
        return ans;
    }
    
    int main() {
        init();
        m = read(), n = read();
        S = 0, T = n+m+1;
        node_num = T;
        int sum = 0;
        for (int i = 1, w; i <= m; ++ i) {
            scanf("%d", &w), sum += w;
            Add_Edge(S, i, w);
            while(getchar() == ' ') {
                scanf("%d", &w);
                Add_Edge(i, m+w,inf);
            }
        }
        for (int i = 1, w; i <= n; ++ i) {
            w = read();
            Add_Edge(i+m, T, w);
        }
        sum -= Dinic();
        for (int i = 1; i <= m; i++)
            if (~dis[i])
                printf("%d ",i);
        printf("\n");
        for (int i = 1; i <= n; i++)
            if (~dis[m+i])
                printf("%d ", i);
        printf("\n%d\n", sum);
        return 0;
    }
    View Cod

    P3410 拍照

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    #define pii pair<long long, int>
    typedef long long ll;
    
    const int maxn = 1e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const ll inf = 1e18;
    const int mod = 1e9 + 7;
    
    
    struct Edge{
        int to;
        int next;
        ll w;
    } edge[maxn*2];
    
    int head[maxn], node_num;
    int cur[maxn];//当前弧优化数组
    int n, m, S, T, k;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    bool vis[maxn];
    
    inline void init(){
        cnt = 0;
        for (int i = 0; i <= node_num; ++ i) head[i] = -1;
    }
    
    inline void Add_Edge(int u, int v, ll w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    
        edge[cnt].next = head[v];
        edge[cnt].to = u;
        edge[cnt].w = 0;
        head[v] = cnt++;
    }
    
    
    inline bool Bfs(){
        for(int i = 0; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[S] = 0;
        queue<int> q;
        q.push(S);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[T] != -1;
    }
    
    inline ll dfs(int u, ll flow){
        if(u == T) return flow;
        ll del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                ll ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline ll Dinic() {
        ll ans = 0;
        while(Bfs()) {
            for(int i = 0; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(S, inf);
        }
        return ans;
    }
    
    int main() {
        scanf("%d %d", &m, &n);
        S = 0, T = n+m+1;
        node_num = T;
        init();
        int sum = 0;
        for (int i = 1, temp; i <= m; ++ i) {
            int cost;
            scanf("%d", &cost), sum += cost;
            Add_Edge(i+n, T, cost);
            while (scanf("%d", &temp) && temp)
                Add_Edge(temp, i+n, inf);
        }
        for (int i = 1, cost; i <= n; ++ i)
            scanf("%d", &cost), Add_Edge(S, i, cost);
        printf("%d\n", sum-Dinic());
        return 0;
    }
    View Code

    P3872 [TJOI2010]电影迷

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    #define pii pair<long long, int>
    typedef long long ll;
    
    const int maxn = 1e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const ll inf = 1e18;
    const int mod = 1e9 + 7;
    
    
    struct Edge{
        int to;
        int next;
        ll w;
    } edge[maxn*2];
    
    int head[maxn], node_num;
    int cur[maxn];//当前弧优化数组
    int n, m, S, T, k;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    bool vis[maxn];
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof(head));
    }
    
    inline void Add_Edge(int u, int v, ll w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    
        edge[cnt].next = head[v];
        edge[cnt].to = u;
        edge[cnt].w = 0;
        head[v] = cnt++;
    }
    
    
    inline bool Bfs(){
        for(int i = 0; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[S] = 0;
        queue<int> q;
        q.push(S);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[T] != -1;
    }
    
    inline ll dfs(int u, ll flow){
        if(u == T) return flow;
        ll del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                ll ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline ll Dinic() {
        ll ans = 0;
        while(Bfs()) {
            for(int i = 0; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(S, inf);
        }
        return ans;
    }
    
    int main() {
        scanf("%d %d", &n, &m);
        S = 0, T = n+1;
        node_num = T;
        init();
        int sum = 0;
        for (int i = 1, w; i <= n; ++ i) {
            scanf("%d", &w);
            if (w > 0) Add_Edge(S, i, w), sum += w;
            else Add_Edge(i, T, -w);
        }
    
        for (int i = 1,u,v,w; i <= m; ++ i) {
            scanf("%d %d %d", &u, &v, &w);
            Add_Edge(u, v, w);
        }
        cout << sum - Dinic() << endl;
        return 0;
    }
    View Code

    P4174 [NOI2006]最大获利

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    #define pii pair<int, int>
    typedef long long ll;
    
    const int maxn = 2e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    
    struct Edge{
        int to;
        int next;
        int w;
    } edge[maxn*2];
    
    int head[maxn], node_num;
    int cur[maxn];//当前弧优化数组
    int n, m, S, T, k;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof(head));
    }
    
    inline void Add_Edge(int u, int v, int w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    
        edge[cnt].next = head[v];
        edge[cnt].to = u;
        edge[cnt].w = 0;
        head[v] = cnt++;
    }
    
    
    inline bool Bfs(){
        for(int i = 0; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[S] = 0;
        queue<int> q;
        q.push(S);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[T] != -1;
    }
    
    inline int dfs(int u, int flow){
        if(u == T) return flow;
        int del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                int ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline int Dinic() {
        int ans = 0;
        while(Bfs()) {
            for(int i = 0; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(S, inf);
        }
        return ans;
    }
    
    inline int read()
    {
        int x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    
    int main() {
        n = read(), m = read();
        S = 0, T = n+m+1;
        node_num = T;
        init();
        int sum = 0;
        for (int i = 1, ci; i <= n; ++ i) {
            ci = read();
            Add_Edge(m+i, T, ci);
        }
        for (int i = 1,u,v,w; i <= m; ++ i) {
            u = read(), v = read(), w = read();
            Add_Edge(S, i, w);
            sum += w;
            Add_Edge(i, u+m, inf);
            Add_Edge(i, v+m, inf);
        }
        cout << sum - Dinic() << endl;
        return 0;
    }
    View Code

    P4313 文理分科

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    #define pii pair<int, int>
    typedef long long ll;
    
    const int maxn = 2e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    
    struct Edge{
        int to;
        int next;
        int w;
    } edge[maxn*2];
    
    int head[maxn], node_num;
    int cur[maxn];//当前弧优化数组
    int n, m, S, T, k;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof(head));
    }
    
    inline void Add_Edge(int u, int v, int w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    
        edge[cnt].next = head[v];
        edge[cnt].to = u;
        edge[cnt].w = 0;
        head[v] = cnt++;
    }
    
    
    inline bool Bfs(){
        for(int i = 0; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[S] = 0;
        queue<int> q;
        q.push(S);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[T] != -1;
    }
    
    inline int dfs(int u, int flow){
        if(u == T) return flow;
        int del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                int ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline int Dinic() {
        int ans = 0;
        while(Bfs()) {
            for(int i = 0; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(S, inf);
        }
        return ans;
    }
    
    inline int read()
    {
        int x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int dic[5][2] = {1,0,-1,0,0,-1,0,1,0,0};
    
    int main()
    {
        n=read(),m=read();
        S = 0, T = 3*n*m+1;
        node_num =3*n*m+1;
        int sum = 0;
        init();
        for (int i=1;i<=n;i++)
        {
            for (int j=1;j<=m;j++)
            {
                int tmp=read();
                Add_Edge(S,(i-1)*m+j,tmp);
                sum+=tmp;
            }
        }
        for (int i=1;i<=n;i++)
        {
            for (int j=1;j<=m;j++)
            {
                int tmp=read();
                Add_Edge((i-1)*m+j,T,tmp);
                sum+=tmp;
            }
        }
        for (int i=1;i<=n;i++)
        {
            for (int j=1;j<=m;j++)
            {
                int tmp=read();
                Add_Edge(S,n*m+(i-1)*m+j,tmp);
                sum+=tmp;
            }
        }
        for (int i=1;i<=n;i++)
        {
            for (int j=1;j<=m;j++)
            {
                int tmp=read();
                Add_Edge(2*n*m+(i-1)*m+j,T,tmp);
                sum+=tmp;
            }
        }
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++)
            {
                for (int k=0;k<5;k++)
                {
                    int nx=i+dic[k][0],ny=j+dic[k][1];
                    if (nx<1 || nx>n || ny<1 || ny>m)
                        continue;
                    Add_Edge(n*m+(nx-1)*m+ny,(i-1)*m+j,inf);
                    Add_Edge((i-1)*m+j,2*n*m+(nx-1)*m+ny,inf);
                }
            }
        cout << sum-Dinic() << endl;
        return 0;
    }
    View Code

    较为经典的最小割:

    P2774 方格取数问题

    View Code

    P2598 [ZJOI2009]狼和羊的故事

    View Code

    P4474 王者之剑

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    
    struct Edge{
        int to;
        int next;
        int w;
    }edge[maxn*2];
    
    int head[maxn];
    int cur[maxn];//当前弧优化数组
    int n, m, S, T;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    int node_num;
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
    }
    
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        for ( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
        for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
        return x * f;
    }
    
    inline void Add_Edge(int u, int v, int w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    
        edge[cnt].next = head[v];
        edge[cnt].to = u;
        edge[cnt].w = 0;
        head[v] = cnt++;
    }
    
    inline bool Bfs(){
        for(int i = 0; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[S] = 0;
        queue<int> q;
        q.push(S);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[T] != -1;
    }
    
    inline int dfs(int u, int flow){
        if(u == T) return flow;
        int del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                int ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline int Dinic(){
        int ans = 0;
        while(Bfs()){
            for(int i = 0; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(S, inf);
        }
        return ans;
    }
    
    int g[205][205];
    int dic[4][2] = {1,0, -1,0, 0,-1, 0,1};
    
    int main() {
        init();
        scanf("%d %d", &n, &m);
        S = 0, T = n*m+1;
        node_num = T;
        int sum = 0;
        for (int i = 1; i <= n; ++ i)
            for (int j = 1; j <= m; ++ j)
                scanf("%d", &g[i][j]), sum += g[i][j];
    
        for (int i = 1; i <= n; ++ i) {
            for (int j = 1; j <= m; ++ j) {
                int id = (i-1)*m+j;
                if ((i+j) % 2 == 0) {
                    Add_Edge(S, id, g[i][j]);
                    for (int k = 0; k < 4; ++ k) {
                        int tx = i + dic[k][0], ty = j + dic[k][1];
                        int id1 = (tx-1)*m+ty;
                        if (tx < 1 || ty < 1 || tx > n || ty > m) continue;
                        Add_Edge(id, id1, inf);
                    }
                }
                else Add_Edge(id, T, g[i][j]);
            }
        }
        printf("%d\n",sum - Dinic());
        return 0;
    }
    View Code



    二分图网络流(Dinic跟二分图跟配哦):

    最大匹配:

    P2071 座位安排

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    
    struct Edge{
        int to;
        int next;
        int w;
    }edge[maxn*2];
    
    int head[maxn];
    int cur[maxn];//当前弧优化数组
    int n, m, s, t, x;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    int node_num;
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
    }
    
    inline void Add_Edge(int u, int v, int w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    }
    
    inline bool Bfs(){
        for(int i = 1; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[s] = 0;
        queue<int> q;
        q.push(s);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[t] != -1;
    }
    
    inline int dfs(int u, int flow){
        if(u == t) return flow;
        int del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                int ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline int Dinic(){
        int ans = 0;
        while(Bfs()){
            for(int i = 1; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(s, inf);
        }
        return ans;
    }
    
    int main(){
        init();
        scanf("%d",&n);
        node_num = 2+n*3;
        s = 1, t = 2+n*3;
        for (int i = 1, a, b; i <= n*2; ++ i) {
            scanf("%d %d", &a, &b);
            a += 1+n*2, b += 1+n*2;
            Add_Edge(s, i+1, 1), Add_Edge(i+1, s, 0);
            Add_Edge(i+1, a, 1), Add_Edge(a, i+1, 0);
            Add_Edge(i+1, b, 1), Add_Edge(b, i+1, 0);
        }
        for (int i = 1; i <= n; ++ i)
            Add_Edge(i+2*n+1, t, 2), Add_Edge(t, i+2*n+1, 0);
    
        int ans = Dinic();
        printf("%d\n", ans);
        return 0;
    }
    View Code

    CF387D George and Interesting Graph

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e4 + 10;
    const int maxm = 1e5 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    
    struct Edge{
        int to;
        int next;
        int w;
    }edge[maxn*2];
    
    int head[maxn];
    int cur[maxn];//当前弧优化数组
    int n, m, s, t, k;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    int node_num;
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
    }
    
    inline void Add_Edge(int u, int v, int w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    }
    
    inline bool Bfs(){
        for(int i = 1; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[s] = 0;
        queue<int> q;
        q.push(s);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[t] != -1;
    }
    
    inline int dfs(int u, int flow){
        if(u == t) return flow;
        int del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                int ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline int Dinic(){
        int ans = 0;
        while(Bfs()){
            for(int i = 1; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(s, inf);
        }
        return ans;
    }
    
    int main(){
        scanf("%d %d", &n, &m);
        s = 1, t = n*2+2;
        node_num = n*2+2;
        int ans = 1000000;
        int in[n+1] = {0}, out[n+1] = {0};
        pair<int, int> rec[maxn];
        for (int i = 1, u, v; i <= m; i++) {
            scanf("%d %d", &u, &v);
            ++out[u], ++in[v];
            if (u == v) in[v]--;
            rec[i] = {u, v};
        }
    
        for (int i = 1 ; i <= n; ++ i) {
            init();
            int temp = in[i]+out[i];
            for (int j = 1; j <= n; ++ j)
                Add_Edge(s,j+1,1), Add_Edge(j+1,s,0), Add_Edge(j+n+1,t,1), Add_Edge(t,j+n+1,0);
            for (int j = 1; j <= m; ++ j) {
                if (rec[j].first == i || rec[j].second == i) continue;
                Add_Edge(rec[j].first+1, rec[j].second+1+n, 1), Add_Edge(rec[j].second+1+n, rec[j].first+1, 0);
            }
            ans = min(ans, n-1-2*Dinic()+m+2*n-1-2*temp);
        }
        printf("%d\n", ans);
        return 0;
    }
    View Code

    P2526 [SHOI2001]小狗散步

    这一题输出匹配的方式挺有用的。边权为0的边代表是最大流边

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e7 + 10;
    const int maxm = 1e5 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    
    struct Edge{
        int to;
        int next;
        int w;
    }edge[maxn*2];
    
    int head[maxn];
    int cur[maxn];//当前弧优化数组
    int n, m, s, t, k, r, d;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    int node_num;
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
    }
    
    inline void Add_Edge(int u, int v, int w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    
        edge[cnt].next = head[v];
        edge[cnt].to = u;
        edge[cnt].w = 0;
        head[v] = cnt++;
    }
    
    inline bool Bfs(){
        for(int i = 0; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[s] = 0;
        queue<int> q;
        q.push(s);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[t] != -1;
    }
    
    inline int dfs(int u, int flow){
        if(u == t) return flow;
        int del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                int ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline int Dinic(){
        int ans = 0;
        while(Bfs()){
            for(int i = 0; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(s, inf);
        }
        return ans;
    }
    
    double cal(int x1, int y1, int x2, int y2)
    {
        return sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
    }
    
    int main() {
    
        cnt = 0;
        memset(head, -1, sizeof(head));
        scanf("%d%d", &n, &m);
        s = 1, t = n+m+2;
        node_num = t;
        pair<int, int> rec_n[n+1], rec_m[m+1];
        for(int i = 1, u, v; i <= n; i ++)
            scanf("%d %d", &rec_n[i].first, &rec_n[i].second);
        for(int i = 1, u, v; i <= m; i ++)
            scanf("%d %d", &rec_m[i].first, &rec_m[i].second);
        for (int i = 2; i <= n ; ++ i) {
            for (int j = 1; j <= m; ++ j) {
                int u1 = rec_n[i-1].first, v1 = rec_n[i-1].second,
                    u2 = rec_n[i].first, v2 = rec_n[i].second,
                    u3 = rec_m[j].first, v3 = rec_m[j].second;
                if (2*cal(u1, v1, u2, v2) > (cal(u1, v1, u3, v3)+ cal(u2, v2, u3, v3)))
                    Add_Edge(i+1, j+n+1, 1);
            }
        }
        for (int i = 2; i <= n ; ++ i)
            Add_Edge(s, i+1, 1);
        for (int i = 1; i <= m; ++ i)
            Add_Edge(i+n+1, t, 1);
        printf("%d\n%d %d ", n+Dinic(), rec_n[1].first, rec_n[1].second);
        for (int i = 2; i <= n; i++) {
            for (int j = head[i+1]; ~j; j = edge[j].next) {
                int v = edge[j].to;
                if (v == s || v == t || edge[j].w) continue;
                printf("%d %d ", rec_m[v-n-1].first, rec_m[v-n-1].second);
            }
            printf("%d %d ", rec_n[i].first, rec_n[i].second);
        }
        return 0;
    }
    View Code

    最大独立集:

    P5030 长脖子鹿放置

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    
    struct Edge{
        int to;
        int next;
        int w;
    }edge[maxn*2];
    
    int head[maxn];
    int cur[maxn];//当前弧优化数组
    int n, m, s, t, k;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    int node_num;
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
    }
    
    inline void Add_Edge(int u, int v, int w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    }
    
    inline bool Bfs(){
        for(int i = 1; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[s] = 0;
        queue<int> q;
        q.push(s);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[t] != -1;
    }
    
    inline int dfs(int u, int flow){
        if(u == t) return flow;
        int del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                int ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline int Dinic(){
        int ans = 0;
        while(Bfs()){
            for(int i = 1; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(s, inf);
        }
        return ans;
    }
    int g[205][205];
    int dic[8][2] = {1,3, -1,3, 1,-3, -1,-3, 3,1, 3,-1, -3,1, -3,-1};
    
    bool check(int tx, int ty)
    {
        return (tx < 1 || ty < 1 || ty > m || tx > n || g[tx][ty]);
    }
    
    int main(){
        init();
        scanf("%d %d %d", &n, &m, &k);
        s = 1, t = n*m+2;
        node_num = n*m+2;
        int ans = 0;
        for (int i = 1, u, v; i <= k; i++)
            scanf("%d %d", &u, &v), ans -= g[u][v]&1,  g[u][v]= 1;
        for (int i = 1 ; i <= n; ++ i) {
            for (int j = 1; j <= m; ++ j) {
                if (g[i][j]) continue;
                int id1 = (i-1)*m+1+j;
                if (i & 1) {
                    Add_Edge(s, id1, 1), Add_Edge(id1, s, 0);
                    for (int k = 0; k < 8; ++ k) {
                        int tx = i + dic[k][0], ty = j + dic[k][1];
                        int id2 = (tx-1)*m+ty+1;
                        if (!check(tx, ty))
                            Add_Edge(id1, id2, 1), Add_Edge(id2, id1, 0);
                    }
                }
                else Add_Edge(id1, t, 1), Add_Edge(t, id1, 0);
            }
        }
        printf("%d\n", n*m-ans-Dinic()-k);
        return 0;
    }
    View Code

    P3033 [USACO11NOV]Cow Steeplechase G

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    
    struct Edge{
        int to;
        int next;
        int w;
    }edge[maxn*2];
    
    int head[maxn];
    int cur[maxn];//当前弧优化数组
    int n, m, S, T, p;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    int node_num;
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
    }
    
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        for ( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
        for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
        return x * f;
    }
    
    inline void Add_Edge(int u, int v, int w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    
        edge[cnt].next = head[v];
        edge[cnt].to = u;
        edge[cnt].w = 0;
        head[v] = cnt++;
    }
    
    inline bool Bfs(){
        for(int i = 0; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[S] = 0;
        queue<int> q;
        q.push(S);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[T] != -1;
    }
    
    inline int dfs(int u, int flow){
        if(u == T) return flow;
        int del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                int ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline int Dinic(){
        int ans = 0;
        while(Bfs()){
            for(int i = 0; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(S, inf);
        }
        return ans;
    }
    
    struct LINE
    {
        int x1,y1, x2,y2;
    };
    
    bool judge(LINE a, LINE b)
    {
        return b.x1<=a.x1&&a.x1<=b.x2&&a.y1<=b.y1&&b.y1<=a.y2;
    }
    int main() {
        init();
        scanf("%d", &n);
        S = 0, T = n+1;
        node_num = T;
        LINE A[2*n+1], B[2*n+1];
        int ca = 0, cb = 0;
        for (int i = 1, x1,x2,y1,y2; i <= n; ++ i) {
            scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
            if (x1 > x2) swap(x1, x2);
            if (y1 > y2) swap(y1, y2);
            if (x1 == x2) A[++ca] = {x1,y1,x2,y2};
            else B[++cb] = {x1,y1,x2,y2};
        }
    
        for (int i = 1; i <= ca; ++ i) Add_Edge(S, i, 1);
        for (int i = 1; i <= cb; ++ i) Add_Edge(i+ca, T, 1);
        for (int i = 1; i <= ca; ++ i)
            for (int j = 1; j <= cb; ++ j)
                if (judge(A[i], B[j]))
                    Add_Edge(i, ca+j, 1);
        printf("%d\n", n - Dinic());
        return 0;
    }
    View Code

    P4304 [TJOI2013]攻击装置

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 300+10;
    const int maxm = 100000+100;
    const int inf = 0x3f3f3f3f;
    
    int n, m, r, c;
    int tot, head[maxm];
    int ans, linkx[maxm], linky[maxm];
    int dx[maxm], dy[maxm];
    char g[maxn][maxn];
    int id[maxn][maxn];
    int dir[8][2]={-1,2,-1,-2, 1,2,1,-2, 2,1, 2,-1, -2,1,-2,-1};
    struct E {
        int to, next;
    }edge[maxm]; //这里千万要注意,如果题目是双向边的话,这里的N要开2*N
    
    inline void read(int& ans)
    {
        int x = 0, f = 1;
        char ch = getchar();
        while (ch<'0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while ( ch >= '0' && ch <= '9') {
            x = x * 10 + ch - '0';
            ch = getchar();
        }
        ans =  x * f;
    }
    
    inline void add_edge(int u, int v) {
        edge[tot].to = v;
        edge[tot].next = head[u];
        head[u] = tot++;
        if (!linkx[u] && !linky[v])
            linky[v] = u, linkx[u] = v, ++ ans;
    }
    
    void init()
    {
        tot = ans = 0;
        memset(head, -1, sizeof(head));
        memset(linkx, 0, sizeof(linkx));
        memset(linky, 0, sizeof(linky));
    }
    
    bool bfs()
    {
        bool ret = 0;
        queue<int> q;
        memset(dx, 0, sizeof(dx)), memset(dy, 0, sizeof(dy));
        for (int i = 1; i <= n*n; ++ i)
            if (!linkx[i]) q.push(i);
        while (!q.empty()) {
            int u = q.front(); q.pop();
            for (int i = head[u]; ~i; i = edge[i].next) {
                int v = edge[i].to;
                if (!dy[v]) {
                    dy[v] = dx[u] + 1;
                    if (!linky[v]) ret = 1;
                    else dx[linky[v]] = dy[v]+1, q.push(linky[v]);
                }
            }
        }
        return ret;
    }
    
    bool dfs(int u)
    {
        for (int i = head[u]; ~i; i = edge[i].next) {
            int v = edge[i].to;
            if (dy[v] == dx[u] + 1) {
                dy[v] = 0;
                if (!linky[v] || dfs(linky[v])) {
                    linky[v] = u, linkx[u] = v;
                    return 1;
                }
            }
        }
        return 0;
    }
    
    int main()
    {
        init();
        ios::sync_with_stdio(0);
        cin.tie(0);
        cin >> n;
        for (int i = 1; i <= n; ++ i)
            for (int j = 1; j <= n; ++ j)
                cin >> g[i][j], id[i][j] = (i-1)*n+j;
        int res = 0;
        for (int i = 1; i <= n; ++ i) {
            for (int j = 1; j <= n; ++ j) {
                if (g[i][j] == '0') {
                    ++ res;
                    for (int k = 0; k < 8; ++ k) {
                        int tx = i + dir[k][0], ty = j+ dir[k][1];
                        if (ty < 1 || ty > n || tx < 1 || tx > n || g[tx][ty] == '1') continue;
                        add_edge(id[i][j], id[tx][ty]);
                    }
                }
            }
        }
        while (bfs()) {
            for (int i = 1; i <= n*n; ++ i)
                if (!linkx[i] && dfs(i))
                    ++ ans;
        }
        cout << res-ans/2 << endl;
      //这段循环是用来输出跟谁匹配
    //    printf("%d\n", ans);
    //    for (int i = 1; i <= n; ++ i)
    //        if (linkx[i]) printf("%d %d\n",i, linkx[i]);
        return 0;
    }
    View Code

    最小路径覆盖:

    P2172 [国家集训队]部落战争

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    
    struct Edge{
        int to;
        int next;
        int w;
    }edge[maxn*2];
    
    int head[maxn];
    int cur[maxn];//当前弧优化数组
    int n, m, s, t, k, r, c;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    int node_num;
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
    }
    
    inline void Add_Edge(int u, int v, int w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    }
    
    inline bool Bfs(){
        for(int i = 1; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[s] = 0;
        queue<int> q;
        q.push(s);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[t] != -1;
    }
    
    inline int dfs(int u, int flow){
        if(u == t) return flow;
        int del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                int ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline int Dinic(){
        int ans = 0;
        while(Bfs()){
            for(int i = 1; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(s, inf);
        }
        return ans;
    }
    
    char g[205][205];
    int id[205][205];
    int dir[2][2]={1,-1,1,1};
    int main(){
        cnt = 0;
        memset(head, -1, sizeof(head));
    
        scanf("%d %d %d %d", &n, &m, &r, &c);
        s = 1, t = n*m*2+2;
        node_num = t;
    
        for (int i = 1; i <= n; ++ i)
            for (int j = 1; j <= m; ++ j)
                cin >> g[i][j], id[i][j] = (i-1)*m+j+1;
        int res = 0;
        for (int i = 1; i <= n; ++ i) {
            for (int j = 1; j <= m; ++ j) {
                Add_Edge(s, id[i][j], 1), Add_Edge(id[i][j], s, 0);
                Add_Edge(id[i][j] + n*m, t, 1), Add_Edge(t, id[i][j] + n*m, 0);
                if (g[i][j] == '.') {
                    ++ res;
                    for (int k = 0; k < 2; ++ k) {
                        int tx = i + r*dir[k][0], ty = j+ c*dir[k][1];
                        if (ty < 1 || ty > m || tx < 1 || tx > n || g[tx][ty] == 'x') continue;
                        Add_Edge(id[i][j], id[tx][ty]+n*m, 1), Add_Edge(id[tx][ty]+n*m, id[i][j], 0);
                    }
                    for (int k = 0; k < 2; ++ k) {
                        int tx = i + c*dir[k][0], ty = j + r*dir[k][1];
                        if (ty < 1 || ty > m || tx < 1 || tx > n || g[tx][ty] == 'x') continue;
                        Add_Edge(id[i][j], id[tx][ty]+n*m, 1), Add_Edge(id[tx][ty]+n*m, id[i][j], 0);
                    }
                }
            }
        }
    
        printf("%d\n", res-Dinic());
        return 0;
    }
    View Code

    P2764 最小路径覆盖问题

    ha之前用二分图刷了就没用dinic了

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 501;
    const int maxm = 250001;
    const int inf = 0x3f3f3f3f;
    
    int n,  m;
    int tot, head[maxn];
    int ans, linkx[maxn], linky[maxn];
    int dx[maxn], dy[maxn];
    
    struct E {
        int to, next;
    }edge[maxm]; //这里千万要注意,如果题目是双向边的话,这里的N要开2*N
    
    inline void read(int& ans)
    {
        int x = 0, f = 1;
        char ch = getchar();
        while (ch<'0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while ( ch >= '0' && ch <= '9') {
            x = x * 10 + ch - '0';
            ch = getchar();
        }
        ans =  x * f;
    }
    void inti()
    {
    
    }
    //加边
    inline void add_edge(int u, int v) {
        edge[tot].to = v;
        edge[tot].next = head[u];
        head[u] = tot++;
        if (!linkx[u] && !linky[v])
            linky[v] = u, linkx[u] = v, ++ ans;
    }
    
    bool bfs()
    {
        bool ret=0;
        queue<int> q;
        memset(dx, 0, sizeof(dx)), memset(dy, 0, sizeof(dy));
        for (int i = 1; i <= n; ++ i)
            if (!linkx[i]) q.push(i);
        while (!q.empty()) {
            int u = q.front(); q.pop();
            for (int i = head[u]; ~i; i = edge[i].next) {
                int v = edge[i].to;
                if (!dy[v]) {
                    dy[v] = dx[u] + 1;
                    if (!linky[v]) ret = 1;
                    else dx[linky[v]] = dy[v]+1, q.push(linky[v]);
                }
            }
        }
        return ret;
    }
    
    bool dfs(int u)
    {
        for (int i = head[u]; ~i; i = edge[i].next) {
            int v = edge[i].to;
            if (dy[v] == dx[u] + 1) {
                dy[v] = 0;
                if (!linky[v] || dfs(linky[v])) {
                    linky[v] = u, linkx[u] = v;
                    return 1;
                }
            }
        }
        return 0;
    }
    
    int main()
    {
        int a, b;
        memset(head, -1, sizeof(head));
        read(n), read(m);
        for (int i = 1; i <= m; ++ i)
            read(a), read(b), add_edge(a,b);
    
        while(bfs()) {
            for (int i = 1; i <= n; ++ i)
                if (!linkx[i] && dfs(i))
                    ++ ans;
        }
        bool vis[n+1] = {0};
        stack<int> s;
        for (int i = 1; i <= n; ++ i) {
            if (vis[i]) continue;
            int cnt = 0;
            int t = i;
            int res[n+1];
            vis[t] = 1;
            s.push(t);
            while (linky[t]) {
                t = linky[t];
                s.push(t);
                vis[t] = 1;
            }
            while (!s.empty()) {
                res[cnt++] = s.top();
                s.pop();
            }
            t = i;
            while (linkx[t]) {
                t = linkx[t];
                res[cnt++] = t;
                vis[t] = 1;
            }
            for (int i = 0; i < cnt-1; ++ i)
                cout << res[i] << " ";
            cout << res[cnt-1] << endl;
        }
        printf("%d\n",n-ans);
    //  这段循环是用来输出跟谁匹配
    //    for (int i = 1; i <= n; ++ i)
    //        printf("%d ",linkx[i]);
    
        return 0;
    }
    View Code

    二分答案 + 网络流check

    P2857 [USACO06FEB]Steady Cow Assignment G

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    //const int maxm = 1e3 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    int m,n,s,t, x, head[maxn], num_edge;
    int cur[maxn],deep[maxn],last[maxn],num[maxn];
    int node_num;
    int cap[40];
    int wanted[maxn][40];
    //cur当前弧优化; last该点的上一条边; num桶 用来GAP优化
    struct Edge{
        int next,to,dis;
    }edge[maxn*2];
    
    void add_edge(int from,int to,int dis)
    {
        edge[num_edge].to=to;
        edge[num_edge].dis=dis;
        edge[num_edge].next=head[from];
        head[from]=num_edge++;
    }
    //bfs仅用于更新deep
    void bfs(int t)
    {
        queue<int>q;
        for (int i=0; i<=node_num; i++) cur[i]=head[i];
        for (int i=1; i<=node_num; i++) deep[i]=node_num;
        deep[t]=0;
        q.push(t);
        while (!q.empty())
        {
            int now=q.front(); q.pop();
            for (int i=head[now]; i != -1; i=edge[i].next)
            {
                if (deep[edge[i].to]==node_num && edge[i^1].dis)//i^1是为了找反边
                {
                    deep[edge[i].to] = deep[now]+1;
                    q.push(edge[i].to);
                }
            }
        }
    }
    
    int add_flow(int s,int t)
    {
        int ans=inf,now=t;
        while (now!=s)
        {
            ans=min(ans,edge[last[now]].dis);
            now=edge[last[now]^1].to;
        }
        now=t;
        while (now!=s)
        {
            edge[last[now]].dis-=ans;
            edge[last[now]^1].dis+=ans;
            now=edge[last[now]^1].to;
        }
        return ans;
    }
    int isap(int s,int t)
    {
        int now=s;
        int maxflow = 0;
        bfs(t);//搜出一条增广路
        for (int i=1; i<=node_num; i++) num[deep[i]]++;
        while (deep[s]<node_num)
        {
            if (now==t)
            {//如果到达汇点就直接增广,重新回到源点进行下一轮增广
                maxflow+=add_flow(s,t);
                now=s;//回到源点
            }
            bool has_find=0;
            for (int i=cur[now]; i!=-1; i=edge[i].next)
            {
                if (deep[now]==deep[edge[i].to]+1 && edge[i].dis)//找到一条增广路
                {
                    has_find=true;
                    cur[now]=i;//当前弧优化
                    now=edge[i].to;
                    last[edge[i].to]=i;
                    break;
                }
            }
            if (!has_find)//没有找到出边,重新编号
            {
                int minn=node_num-1;
                for (int i=head[now]; i!=-1; i=edge[i].next)//回头找路径
                    if (edge[i].dis)
                        minn=min(minn,deep[edge[i].to]);
                if ((--num[deep[now]])==0) break;//GAP优化 出现了断层
                num[deep[now]=minn+1]++;
                cur[now]=head[now];
                if (now!=s)
                    now=edge[last[now]^1].to;
            }
        }
        return maxflow;
    }
    
    bool check(int range)
    {
        for (int i = 1; i + range - 1 <= m; ++ i) {
            num_edge = 0;
            memset(head,-1,sizeof(head));
            for (int j = 1; j <= m; ++ j) {
                int barn = n+1+j;
                add_edge(barn, t, cap[j]), add_edge(t, barn, 0);
            }
            for (int j = 2; j <= n+1; ++ j) {
                add_edge(s, j, 1), add_edge(j, s, 0);
                for (int k = 0; k <= range-1; ++ k) {
                    int barn = n+1+wanted[j][k+i];
                    add_edge(j, barn, 1), add_edge(barn, j, 0);
                }
            }
            if (isap(s,t) == n) return 1;
        }
        return 0;
    }
    
    
    int main(){
        scanf("%d %d", &n, &m);
        node_num = n+m+2;
        s = 1, t = n+m+2;
        for (int i = 2; i <= n+1; ++ i)
            for (int j = 1; j <= m; ++ j)
                scanf("%d", &wanted[i][j]);
        for (int i = 1; i <= m; ++ i)
            scanf("%d", &cap[i]);
        //整数二分答案
        int left = 0, right = m, ans = 40;
        while(left <= right) {
            int mid = (left + right) / 2;
            if (check(mid)) {
                right = mid - 1;
                ans = min(ans, mid);
            }
            else
                left = mid + 1;
        }
        printf("%d\n", ans);
    
        return 0;
    }
    View Code

    P2936 [USACO09JAN]Total Flow S

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    //const int maxm = 1e3 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    int m,n,s,t, x, head[maxn], num_edge;
    int cur[maxn],deep[maxn],last[maxn],num[maxn];
    int node_num;
    int cap[40];
    int wanted[maxn][40];
    //cur当前弧优化; last该点的上一条边; num桶 用来GAP优化
    struct Edge{
        int next,to,dis;
    }edge[maxn*2];
    
    void add_edge(int from,int to,int dis)
    {
        edge[num_edge].to=to;
        edge[num_edge].dis=dis;
        edge[num_edge].next=head[from];
        head[from]=num_edge++;
    }
    //bfs仅用于更新deep
    void bfs(int t)
    {
        queue<int>q;
        for (int i=0; i<=node_num; i++) cur[i]=head[i];
        for (int i=1; i<=node_num; i++) deep[i]=node_num;
        deep[t]=0;
        q.push(t);
        while (!q.empty())
        {
            int now=q.front(); q.pop();
            for (int i=head[now]; i != -1; i=edge[i].next)
            {
                if (deep[edge[i].to]==node_num && edge[i^1].dis)//i^1是为了找反边
                {
                    deep[edge[i].to] = deep[now]+1;
                    q.push(edge[i].to);
                }
            }
        }
    }
    
    int add_flow(int s,int t)
    {
        int ans=inf,now=t;
        while (now!=s)
        {
            ans=min(ans,edge[last[now]].dis);
            now=edge[last[now]^1].to;
        }
        now=t;
        while (now!=s)
        {
            edge[last[now]].dis-=ans;
            edge[last[now]^1].dis+=ans;
            now=edge[last[now]^1].to;
        }
        return ans;
    }
    int isap(int s,int t)
    {
        int now=s;
        int maxflow = 0;
        bfs(t);//搜出一条增广路
        for (int i=1; i<=node_num; i++) num[deep[i]]++;
        while (deep[s]<node_num)
        {
            if (now==t)
            {//如果到达汇点就直接增广,重新回到源点进行下一轮增广
                maxflow+=add_flow(s,t);
                now=s;//回到源点
            }
            bool has_find=0;
            for (int i=cur[now]; i!=-1; i=edge[i].next)
            {
                if (deep[now]==deep[edge[i].to]+1 && edge[i].dis)//找到一条增广路
                {
                    has_find=true;
                    cur[now]=i;//当前弧优化
                    now=edge[i].to;
                    last[edge[i].to]=i;
                    break;
                }
            }
            if (!has_find)//没有找到出边,重新编号
            {
                int minn=node_num-1;
                for (int i=head[now]; i!=-1; i=edge[i].next)//回头找路径
                    if (edge[i].dis)
                        minn=min(minn,deep[edge[i].to]);
                if ((--num[deep[now]])==0) break;//GAP优化 出现了断层
                num[deep[now]=minn+1]++;
                cur[now]=head[now];
                if (now!=s)
                    now=edge[last[now]^1].to;
            }
        }
        return maxflow;
    }
    
    void init()
    {
        num_edge = 0;
        memset(head,-1,sizeof(head));
    }
    
    int main()
    {
        init();
        scanf("%d", &n);
        s = 1, t = 26;
        node_num = 100;
        for (int i = 1; i <= n; i++) {
            char tu, tv;
            int u, v, w;
            scanf("\n%c %c %d", &tu, &tv, &w);
            u = tu-64, v = tv-64;
            add_edge(u, v, w);
            add_edge(v, u, 0);//正反向建图
        }
        printf("%d\n", isap(s, t));
        return 0;
    }
    View Code

    P3153 [CQOI2009]跳舞

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    
    struct Edge{
        int to;
        int next;
        int w;
    }edge[maxn*2];
    
    int head[maxn];
    int cur[maxn];//当前弧优化数组
    int n, m, S, T, k;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    int node_num;
    int rec[100+5][100+5];
    
    inline void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
    }
    
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        for ( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
        for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
        return x * f;
    }
    
    inline void Add_Edge(int u, int v, int w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    
        edge[cnt].next = head[v];
        edge[cnt].to = u;
        edge[cnt].w = 0;
        head[v] = cnt++;
    }
    
    inline bool Bfs(){
        for(int i = 0; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[S] = 0;
        queue<int> q;
        q.push(S);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[T] != -1;
    }
    
    inline int dfs(int u, int flow){
        if(u == T) return flow;
        int del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                int ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline int Dinic(){
        int ans = 0;
        while(Bfs()){
            for(int i = 0; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(S, inf);
        }
        return ans;
    }
    
    bool judge(int mid) {
        init();
        for (int i = 1; i <= n; ++ i) {
            Add_Edge(S, i, mid);
            Add_Edge(i, i+n, k);
            for (int j = 1; j <= n; ++j) {
                if (rec[i][j]) Add_Edge(i, j+2*n, 1);
                else Add_Edge(i+n, j+3*n, 1);
            }
        }
        for (int i = 1; i <= n; ++ i) {
            Add_Edge(i+3*n,i+2*n, k);
            Add_Edge(i+2*n, T, mid);
        }
        return Dinic() == mid * n;
    }
    
    int main() {
        init();
        scanf("%d %d", &n, &k);
        S = 0, T = 4*n+1;
        node_num = T;
    
        for (int i = 1; i <= n; ++ i) {
            for (int j = 1; j <= n; ++ j) {
                char temp;
                cin >> temp;
                if (temp == 'Y') rec[i][j] = 1;
            }
        }
    
        int left = 0, right = 100000;
        int ans = 0;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (judge(mid)) {
                left = mid + 1;
                ans = max(ans, mid);
            }
            else
                right = mid - 1;
        }
        cout << ans << endl;
        return 0;
    }
    View Code

    分层图网络流:

    P2754 [CTSC1999]家园 / 星际转移问题

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    //const int maxm = 1e3 * 2 + 10;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    int m,n,S,T,k, x, head[maxn], num_edge;
    int cur[maxn],deep[maxn],last[maxn],num[maxn];
    int node_num;
    int cap[40];
    int wanted[maxn][40];
    //cur当前弧优化; last该点的上一条边; num桶 用来GAP优化
    struct Edge{
        int next,to,dis;
    }edge[maxn*2];
    
    void add_edge(int from,int to,int dis)
    {
        edge[num_edge].to=to;
        edge[num_edge].dis=dis;
        edge[num_edge].next=head[from];
        head[from]=num_edge++;
    
        edge[num_edge].to=from;
        edge[num_edge].dis=0;
        edge[num_edge].next=head[to];
        head[to]=num_edge++;
    }
    //bfs仅用于更新deep
    void bfs(int T)
    {
        queue<int>q;
        for (int i=0; i<=node_num; i++) cur[i]=head[i];
        for (int i=0; i<=node_num; i++) deep[i]=node_num;
        deep[T]=0;
        q.push(T);
        while (!q.empty())
        {
            int now=q.front(); q.pop();
            for (int i=head[now]; i != -1; i=edge[i].next)
            {
                if (deep[edge[i].to]==node_num && edge[i^1].dis)//i^1是为了找反边
                {
                    deep[edge[i].to] = deep[now]+1;
                    q.push(edge[i].to);
                }
            }
        }
    }
    
    int add_flow(int S,int T)
    {
        int ans=inf,now=T;
        while (now!=S)
        {
            ans=min(ans,edge[last[now]].dis);
            now=edge[last[now]^1].to;
        }
        now=T;
        while (now!=S)
        {
            edge[last[now]].dis-=ans;
            edge[last[now]^1].dis+=ans;
            now=edge[last[now]^1].to;
        }
        return ans;
    }
    
    int isap(int S,int T)
    {
        int now=S;
        int maxflow = 0;
        bfs(T);//搜出一条增广路
        for (int i=1; i<=node_num; i++) num[deep[i]]++;
        while (deep[S]<node_num)
        {
            if (now==T)
            {//如果到达汇点就直接增广,重新回到源点进行下一轮增广
                maxflow+=add_flow(S,T);
                now=S;//回到源点
            }
            bool has_find=0;
            for (int i=cur[now]; i!=-1; i=edge[i].next)
            {
                if (deep[now]==deep[edge[i].to]+1 && edge[i].dis)//找到一条增广路
                {
                    has_find=true;
                    cur[now]=i;//当前弧优化
                    now=edge[i].to;
                    last[edge[i].to]=i;
                    break;
                }
            }
            if (!has_find)//没有找到出边,重新编号
            {
                int minn=node_num-1;
                for (int i=head[now]; i!=-1; i=edge[i].next)//回头找路径
                    if (edge[i].dis)
                        minn=min(minn,deep[edge[i].to]);
                if ((--num[deep[now]])==0) break;//GAP优化 出现了断层
                num[deep[now]=minn+1]++;
                cur[now]=head[now];
                if (now!=S)
                    now=edge[last[now]^1].to;
            }
        }
        return maxflow;
    }
    
    void init()
    {
        num_edge = 0;
        memset(head,-1,sizeof(head));
    }
    
    int f[1050], p[1050], r[1050], s[1050][1050];
    
    int Find(int x){
        if(f[x]==x) return x;
        else return f[x]=Find(f[x]);
    }
    
    void un(int a,int b){
        int fa=Find(a),fb=Find(b);
        if(fa!=fb) f[fa]=fb;
    }
    
    
    int main() {
        init();
        scanf("%d%d%d", &n, &m, &k);
        for (int i = 1; i <= n+1; ++ i) f[i] = i;
        for (int i = 0; i < m; i++) {
            scanf("%d%d", &p[i], &r[i]);
            for (int j = 0; j < r[i]; j++) {
                scanf("%d", &s[i][j]);
                if (s[i][j] == -1) s[i][j] = n+1;
                if (j) un(s[i][j], s[i][j-1]);
            }
        }
        if (Find(0) != Find(n+1)) {
            printf("0\n");
        }
        else {
            n += 2;
            S = 1001, T = 1002;
            node_num = 1050;
            add_edge(S, 0, inf);
            add_edge(n-1, T, inf);
            for (int ans = 1; ; ans++) {
                add_edge(S, 0+ans*n, inf);//超级源点向这一时刻的地球连边
                add_edge(n-1+ans*n, T, inf);//这一时刻的月球向超级汇点连边
                for (int i = 1; i < n-1; i++)
                    add_edge(i+(ans-1)*n, i+ans*n, inf);//上下层空间站不动
                for (int i = 0; i < m; i++) {
                    int u = s[i][(ans-1)%r[i]]+(ans-1)*n;
                    int v = s[i][ans%r[i]]+ans*n;
                    add_edge(u, v, p[i]);//通过飞船移动
                }
                k -= isap(S,T);
                if (k <= 0) { printf("%d\n", ans); break; }
            }
        }
        return 0;
    }
    View Code

    网络流与其他奇奇怪怪的结合:

    最短路径图 + 最大流:

    P3171 [CQOI2015]网络吞吐量

    通过dijkstra跑出各点的dist,

    之后通过判断 g[i][j] + dist[i] == dist[j]来判断该点是否在最短路径图上

    之后建边,跑最大流

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    #define pii pair<long long, int>
    typedef long long ll;
    
    const int maxn = 1e6 + 10;
    const int maxm = 1e5 * 2 + 10;
    const ll inf = 1e18;
    const int mod = 1e9 + 7;
    
    
    struct Edge{
        int to;
        int next;
        ll w;
    } edge[maxn*2];
    
    int head[maxn], node_num;
    int cur[maxn];//当前弧优化数组
    int n, m, S, T, k;//点数,边数,源点,汇点
    int dis[maxn];//Bfs深度
    int cnt = 0;//边数
    ll g[505][505];
    ll diss[maxn];
    bool vis[maxn];
    
    inline void init(){
        cnt = 0;
        for (int i = 0; i <= node_num; ++ i)
            head[i] = -1, diss[i] = inf, vis[i] = 0;
        memset(g, -1, sizeof(g));
    }
    
    inline void Add_Edge(int u, int v, ll w){
        edge[cnt].next = head[u];
        edge[cnt].to = v;
        edge[cnt].w = w;
        head[u] = cnt++;
    
        edge[cnt].next = head[v];
        edge[cnt].to = u;
        edge[cnt].w = 0;
        head[v] = cnt++;
    }
    
    
    inline bool Bfs(){
        for(int i = 0; i <= node_num; ++i) dis[i] = -1; //这里要根据你所建的点数来确定
        dis[S] = 0;
        queue<int> q;
        q.push(S);
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(dis[v] == -1 && edge[i].w){//没有标记深度并且有残量
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        return dis[T] != -1;
    }
    
    inline ll dfs(int u, ll flow){
        if(u == T) return flow;
        ll del = flow;
        for(int i = cur[u]; i != -1; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                ll ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    
    inline ll Dinic() {
        ll ans = 0;
        while(Bfs()) {
            for(int i = 0; i <= node_num; ++i) cur[i] = head[i];
            ans += dfs(S, inf);
        }
        return ans;
    }
    
    void dijkstra() {
        priority_queue<pii,vector<pii>,greater<pii> > q;//从小到大
        diss[1] = 0; q.push({diss[1],1});
        while (!q.empty()) {
            int now = q.top().second;
            q.pop();
            if(vis[now]) continue;
            vis[now] = 1;
            for(int v = 1; v <= n; ++ v) {
                if (g[now][v] != -1)
                    if(diss[v] > diss[now] + g[now][v]) {
                        diss[v] = diss[now] + g[now][v];
                        q.push({diss[v],v});
                    }
            }
        }
    }
    
    int main() {
        scanf("%d %d", &n, &m);
        S = 0, T = n+n+1;
        node_num = T;
        init();
        for (int i = 1, u, v; i <= m; ++ i) {
            ll w;
            scanf("%d %d %lld", &u, &v, &w);
            if (g[u][v] != -1) g[u][v] = g[v][u] = min(g[v][u], w);
            else  g[u][v] = g[v][u] = w;
        }
        dijkstra();
        ll rec[n+1];
        Add_Edge(S, 1, inf), Add_Edge(n*2, T, inf);
        for (int i = 1; i <= n; ++ i) {
            scanf("%lld", &rec[i]);
            if (i == 1 || i == n) Add_Edge(i, i+n, inf);
            else Add_Edge(i, i+n, rec[i]);
        }
        for (int u = 1; u <= n; ++ u) {
            for (int v = 1; v <= n; ++ v) {
                if (u == v) continue;
                if (g[u][v] != -1 && diss[v] == g[u][v] + diss[u])
                    Add_Edge(u+n, v, inf);//, cout << u << " "<< v << endl;
            }
        }
    
        printf("%lld\n", Dinic());
        return 0;
    }
    View Code
  • 相关阅读:
    一个疑难杂症 IIS URL区分大小写(FF的自动变换URL问题)?
    炉石传说 C# 设计文档(序)
    炉石传说 C# 开发笔记(BS上线尝试)
    炉石传说 C# 开发笔记(BS模式Demo)
    炉石传说 C# 开发笔记(6月底小结)
    炉石传说 C# 开发笔记 (初版)
    使用python+requests实现接口自动化测试
    SpringMVC之数据传递二
    SpringMVC之数据传递一
    SpringMVC之HandlerMapping的使用
  • 原文地址:https://www.cnblogs.com/Vikyanite/p/13418686.html
Copyright © 2011-2022 走看看