kuangbin 网洛流 part1(有dinic和isap模板)

网络流的一些注意事项

具体可以看这位大佬

1.1最大(瘤)流

1.1.1----ACM Computer Factory POJ - 3436点有限制拆点,边无限制

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

题意:

有一个电脑的生产线,要你优化生产线。

思路:

  1. 对于每台机器都有一个生产量, Q i Qi Qi。(把机器抽象成点,就是点有限制,要拆点)
  2. 如果一台机器的输入 没有包含 “1”,那么就说明这台机器可以和源点 S S S相连。(inf)
  3. 如果一台机器的输出有一个零件不能生成,那么它就不能和汇点 T T T相连。(inf)
  4. 对于一个机器的输出是否可以传递到下一个机器的输入,这里要判断一下,是否要连边。(inf)
  5. 最后就是按照最大流的计算结果,查看边是否有流量,有+flow,那么说明机器有conection(这里要注意一些边界的判断)。

AC

#include <iostream>
#include <vector>
#include <cstring>
#include <queue>
#include <cstdio>
//#include <>
#include <algorithm>
//#include <>
#define sz(a) ((int)a.size())
#define pb push_back
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define eb emplace_back
#define mst(x,a) memset(x,a,sizeof(x))
#define fzhead EDGE(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c),flow(f)
using namespace std;
const int N=100+10;
const int maxn=100+10;
const int M=0;
const int inf=0x3f3f3f3f;
struct EDGE{
    int from,to,cap,flow;
    EDGE(){}
    fzhead:fzbody{}
};
struct Dinic{
    int n,m,s,t;
    vector<EDGE> edges;
    vector<int> g[maxn];
    bool vis[maxn];
    int d[maxn];
    int cur[maxn];
///cur就是记录当前循环到了哪一条边。
    void init(int n){
        this->n = n;
        for(int i=0; i<n; i++)g[i].clear();
        edges.clear();
    }
    void add(int from, int to, int cap){
       // edges.eb(from,to,cap,0);
        //edges.eb(to,from,0,0);
        edges.pb({from,to,cap,0});
        edges.pb({to,from,0,0});
        ///加边同时,加正向和反向。
        m=edges.size();
        g[from].pb(m-2);
        g[to].pb(m-1);
    }
    bool bfs(){
        mst(vis,0);
        mst(d,0);
        queue<int>q;
        q.push(s);
        d[s]=0;
        vis[s]=1;///源点深度为1.
        while(!q.empty())
        {
            int x=q.front();q.pop();
            for(int i=0; i<sz(g[x]); i++)
            {
                EDGE&e=edges[g[x][i]];
                if(!vis[e.to]&&e.cap>e.flow){
                    vis[e.to]=1;
                    d[e.to]=d[x]+1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];///当汇点的深度不存在时,说明不存在分层图。
    }
    int dfs(int x, int a){
        ///x为当前节点,a为流量。
        if(x==t || a==0)return a;///当已经到达汇点,或者流量不存在时,返回。
        int flow=0,f;
        for(int &i=cur[x]; i<sz(g[x]); i++){
///注意这里的“&”符号,这样i增加同时也能改变cur【x】的值,达到弧优化的目的。
            EDGE& e=edges[g[x][i]];
            if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){///判断并且增广。
                e.flow+=f;///加减
                edges[g[x][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if(a==0)break;
            }
        }
        return flow;
    }
    int maxflow(int s, int t){
        this->s=s,this->t=t;
        int flow=0;
        while(bfs()){
///每一次建立分层图后,都要把cur置为每一个点的第一条边
            mst(cur,0);
        flow+=dfs(s,inf);
        }
        return flow;
    }
} dinic;
int n,p;
int a[maxn][20];
int w[maxn];
int main()
{
    while(~scanf("%d%d",&p,&n)){
        dinic.init(maxn);
        int s=2*n+1;
        int t=2*n+2;
        For(i,1,n){
            scanf("%d",w+i);
            For(j,1,p)scanf("%d",a[i]+j);
            For(j,1,p)scanf("%d",a[i+n]+j);
        }
        //cout<<"ok"<<endl;
        For(i,1,n)dinic.add(i,i+n,w[i]);
        For(i,1,n){
            bool fl=true;
            For(j,1,p)if(a[i][j]==1)fl=false;
            if(fl)dinic.add(s,i,inf);
        }
        For(i,n+1,2*n){
            bool fl=true;
            For(j,1,p)if(a[i][j]!=1)fl=false;
            if(fl)dinic.add(i,t,inf);
        }
        For(i,n+1,2*n){
            For(j,1,n){
                bool fl=true;
                For(k,1,p){
                    if(a[i][k]==a[j][k])continue;
                    if(a[j][k]==2)continue;
                    fl=false;
                }if(fl)dinic.add(i,j,inf);
            }
        }
       // cout<<"ok"<<endl;
        int ans=dinic.maxflow(s,t);
        //cout<<"ok"<<endl;
        vector<EDGE>anss;
        vector<EDGE> &e=dinic.edges;
        for(int i=0; i<sz(e); i++){
            if(e[i].from<=n||e[i].from==s)continue;
            if(e[i].to>=n+1)continue;
            if(e[i].flow>0)anss.push_back({e[i].from-n,e[i].to,0,e[i].flow});
        }
        printf("%d %d\n",ans,sz(anss));
        for(int i=0; i<sz(anss); i++)printf("%d %d %d\n",anss[i].from,anss[i].to,anss[i].flow);
    }
    return 0;
}

1.1.2----Dining POJ - 3281点有限制–拆点,边有限制-容量为限制

在这里插入图片描述
在这里插入图片描述

题意:

农夫有 n n n头奶牛,有 f f f个食物,有 d d d个drink
对于每头奶牛有喜欢的 f o o d food food d r i n k drink drink
如何分配,求可以使最多奶牛满足。

思路:

由于奶牛只有一头,点有限制,拆点,其它就是模板。
而食物和drink只有一种,那么边的容量就为限制。

笔记

拆点体会。

对于下图
在这里插入图片描述

如果从 f o o d 1 food1 food1 d r i n k 2 drink2 drink2 操作完后,是这样。
但下次增广时,在碰到这头cow,由于没有进行拆点
牛还是会进行 f o o d 2 food2 food2 d r i n k 1 drink1 drink1

AC

#include <iostream>
#include <vector>
#include <cstring>
#include <queue>
#include <cstdio>
#include <algorithm>
#define sz(a) ((int)a.size())
#define pb push_back
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define eb emplace_back
#define mst(x,a) memset(x,a,sizeof(x))
#define fzhead EDGE(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
const int N=100+10;
const int maxn=100+200+100+10;
const int M=0;
const int inf =0x3f3f3f3f;
struct EDGE{
    int from,to,cap,flow;
    EDGE(){}
    fzhead:fzbody{}
};
struct Dinic{
    int n,m,s,t;
    vector<EDGE> edges;
    vector<int> g[maxn];
    bool vis[maxn];
    int d[maxn];
    int cur[maxn];
///cur就是记录当前循环到了哪一条边。
    void init(int n){
        this->n = n;
        for(int i=0; i<n; i++)g[i].clear();
        edges.clear();
    }
    void add(int from, int to, int cap){
       // edges.eb(from,to,cap,0);
        //edges.eb(to,from,0,0);
        edges.pb({from,to,cap,0});
        edges.pb({to,from,0,0});
        ///加边同时,加正向和反向。
        m=edges.size();
        g[from].pb(m-2);
        g[to].pb(m-1);
    }
    bool bfs(){
        mst(vis,0);
        mst(d,0);
        queue<int>q;
        q.push(s);
        d[s]=0;
        vis[s]=1;///源点深度为1.
        while(!q.empty())
        {
            int x=q.front();q.pop();
            for(int i=0; i<sz(g[x]); i++)
            {
                EDGE&e=edges[g[x][i]];
                if(!vis[e.to]&&e.cap>e.flow){
                    vis[e.to]=1;
                    d[e.to]=d[x]+1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];///当汇点的深度不存在时,说明不存在分层图。
    }
    int dfs(int x, int a){
        ///x为当前节点,a为流量。
        if(x==t || a==0)return a;///当已经到达汇点,或者流量不存在时,返回。
        int flow=0,f;
        for(int &i=cur[x]; i<sz(g[x]); i++){
///注意这里的“&”符号,这样i增加同时也能改变cur【x】的值,达到弧优化的目的。
            EDGE& e=edges[g[x][i]];
            if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){///判断并且增广。
                e.flow+=f;///加减
                edges[g[x][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if(a==0)break;
            }
        }
        return flow;
    }
    int maxflow(int s, int t){
        this->s=s,this->t=t;
        int flow=0;
        while(bfs()){
///每一次建立分层图后,都要把cur置为每一个点的第一条边
            mst(cur,0);
        flow+=dfs(s,inf);
        }
        return flow;
    }
} dinic;
int n,f,d;
int main()
{
    int s=0, t=401,x;
    dinic.init(maxn);
    scanf("%d%d%d", &n,&f,&d);
    For(i,1,f)dinic.add(s,i,1);
    For(i,1,d)dinic.add(i+300,t,1);
    For(i,1,n)dinic.add(i+100,i+200,1);
    For(i,1,n)
    {
        scanf("%d%d", &f, &d);
        For(j,1,f){
            scanf("%d", &x);
            dinic.add(x,i+100,1);
        }
        For(j,1,d){
            scanf("%d", &x);
            dinic.add(i+200,x+300,1);
        }
    }
    int ans=dinic.maxflow(s,t);
    printf("%d\n",ans);
    return 0;
}

1.1.3----A Plug for UNIX POJ - 1087(建图)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

题意:

来自hrbustacm2 019-04-11

AS WE ALL KNOW,最近哈理工出现了一起着火事件,原因是用了杂牌的插座,有着强烈安全意识的鑫爹急忙为G808换上了最牛B的红牛插座。假设他买了n种插座,G808有m个电器,分别有自己可以插的插座。由于鑫爹的插座非常牛B,可以相互转换,接下来给出k行说明S1插座和S2插座把S2换成S1,那么最少有几个电器没有插座用呢?

思路:

源点 − > -> > 插座S − > -> > 设备 − > -> > 汇点
------ 1----------- 1----------- 1
有k个转换器,由于没有限制个数,所以
S 2 S2 S2 − > -> > S 1 S1 S1
------ i n f inf inf

AC

#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <map>
#include <string>
#define sz(a) ((int)a.size())
#define pb push_back
#define mst(x,a) memset(x,a,sizeof(x))
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define fzhead EDGE(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
const int N =100+10;
const int maxn=400+10;
const int M=0;
const int inf=0x3f3f3f3f;
struct EDGE{
    int from,to,cap,flow;
    EDGE(){}
    fzhead:fzbody{}
};
struct Dinic{
    int n,m,s,t;
    vector<EDGE> edges;
    vector<int> g[maxn];
    bool vis[maxn];
    int d[maxn];
    int cur[maxn];
    void init(int n){
        this->n=n;
        for(int i=0; i<n; i++)g[i].clear();
        edges.clear();
    }
    void add(int from, int to, int cap){
        edges.pb({from,to,cap,0});
        edges.pb({to,from,0,0});
        m=edges.size();
        g[from].pb(m-2);
        g[to].pb(m-1);
    }
    bool bfs(){
        mst(vis,0);
        mst(d,0);
        queue<int>q;
        q.push(s);
        d[s]=0;
        vis[s]=1;
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=0; i<sz(g[x]); i++){
                EDGE& e=edges[g[x][i]];
                if(!vis[e.to]&&e.cap>e.flow){
                    vis[e.to]=1;
                    d[e.to]=d[x]+1;
                    q.push(e.to);
                }
            }
        }return vis[t];
    }
    int dfs(int x,int a){
        if(x==t||a==0)return a;
        int flow=0,f;
        for(int &i=cur[x]; i<sz(g[x]); i++){
            EDGE& e=edges[g[x][i]];
            if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){
                e.flow+=f;
                edges[g[x][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if(a==0)break;
            }
        }return flow;
    }
    int maxflow(int s, int t){
        this->s=s,this->t=t;
        int flow=0;
        while(bfs()){
            mst(cur,0);
            flow+=dfs(s,inf);
        }
        return flow;
    }
} dinic;
map<string,int>ma;
int main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int n,m,k;
    cin>>n;
    dinic.init(maxn);
    int tot=0,s=0,t=401;
    string x,x1;
    For(i,1,n){
        cin>>x;
        if(!ma.count(x)){ma[x]=++tot;dinic.add(s,ma[x],1);}
    }
    cin>>m;
    For(i,1,m){
        cin>>x>>x1;
        if(!ma.count(x))ma[x]=++tot;
        if(!ma.count(x1))ma[x1]=++tot;
        dinic.add(ma[x1],ma[x],1);
        dinic.add(ma[x],t,1);
    }
    cin>>k;
    For(i,1,k){
        cin>>x>>x1;
        if(!ma.count(x))ma[x]=++tot;
        if(!ma.count(x1))ma[x1]=++tot;
        dinic.add(ma[x1],ma[x],inf);
    }
    int ans=m-dinic.maxflow(s,t);
    cout<<ans<<endl;
    return 0;
}

1.1.4----Power Network POJ - 1459(多源汇点&&多源)

在这里插入图片描述
在这里插入图片描述

思路:

板子题。

反思

本题的读入。

  1. 关于char,可以直接
    在这里插入图片描述
    在这里插入图片描述
  2. 不过可以stringstream,不过慢一点。

AC

#include <iostream>
#include <queue>
#include <cstring>
#include <string>
#include <vector>
#include <sstream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define pb push_back
#define sz(a) (int)(a.size())
#define mst(x,a) memset(x,a,sizeof(x))
#define fzhead Edge(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
const int maxn=1e2+10;
const int inf=0x3f3f3f3f;
struct Edge
{
    int from,to,cap,flow;
    Edge(){}
    fzhead:fzbody{}
};
struct Dinic{
    int n,m,s,t;
    vector<Edge>edges;
    vector<int>g[maxn];
    bool vis[maxn];
    int d[maxn];
    int cur[maxn];
    void init(int n){
        this->n=n;
        for(int i=0; i<n; i++)g[i].clear();
        edges.clear();
    }
    void add(int from, int to, int cap){
        edges.pb({from,to,cap,0});
        edges.pb({to,from,0,0});
        m=edges.size();
        g[from].pb(m-2);
        g[to].pb(m-1);
    }
    bool bfs(){
        mst(vis,0);mst(d,0);
        queue<int>q;
        q.push(s);
        d[s]=0;
        vis[s]=1;
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=0; i<sz(g[x]); i++){
                Edge&e=edges[g[x][i]];
                if(!vis[e.to]&&e.cap>e.flow){
                    vis[e.to]=1;
                    d[e.to]=d[x]+1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];
    }
    int dfs(int x,int a){
        if(x==t||a==0)return a;
        int flow=0,f;
        for(int &i=cur[x]; i<sz(g[x]); i++){
            Edge&e=edges[g[x][i]];
            if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){
                e.flow+=f;
                edges[g[x][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if(a==0)break;
            }
        }
        return flow;
    }
    int maxflow(int s, int t){
        this->s=s,this->t=t;
        int flow=0;
        while(bfs()){
            mst(cur,0);
            flow+=dfs(s,inf);
        }
        return flow;
    }
} dinic;
int n,m,p,c;
int main()
{
    while(~scanf("%d%d%d%d", &n, &p,&c, &m)){
        dinic.init(maxn);
        int s=101,t=102;
        int u,v,z;
        string str;
        for(int i=1; i<=m; i++){
            cin>>str;
            for(int j=0; j<sz(str); j++)if(str[j]<'0'||str[j]>'9')str[j]=' ';
            stringstream ss(str);
            ss>>u>>v>>z;
           // cout<<u<<' '<<v<<' '<<z<<endl;
            dinic.add(u,v,z);
        }
        for(int i=1; i<=p; i++){
            cin>>str;
            for(int j=0; j<sz(str); j++)if(str[j]<'0'||str[j]>'9')str[j]=' ';
            stringstream ss(str);
            ss>>v>>z;
            //cout<<v<<' '<<z<<endl;
            dinic.add(s,v,z);
        }
        for(int i=1; i<=c; i++){
            cin>>str;
            for(int j=0; j<sz(str); j++)if(str[j]<'0'||str[j]>'9')str[j]=' ';
            stringstream ss(str);
            ss>>u>>z;
          //  cout<<u<<' '<<z<<endl;
            dinic.add(u,t,z);
        }
       // cout<<"ok"<<endl;
        printf("%d\n", dinic.maxflow(s,t));
    }
    return 0;
}

1.1.5----Island Transport HDU - 4280(本题卡dinic)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

题意:

赤裸裸的模板。

AC

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <algorithm>
#include <queue>
#define sz(a) (int)(a.size())
#define pb push_back
#define mst(x,a) memset(x,a,sizeof(x))
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define fzhead Edge(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f;
const int maxm=2e5+10;
struct Edge {
  int from, to, cap, flow;
  Edge(){}// Edge(int u, int v, int c, int f) : from(u), to(v), cap(c), flow(f) {}
  fzhead:fzbody{}
};
//
bool operator<(const Edge& a, const Edge& b) {
  return a.from < b.from || (a.from == b.from && a.to < b.to);
}
//
struct ISAP {
  int n, m, s, t;
  vector<Edge> edges;
  vector<int> G[maxn];
  bool vis[maxn];
  int d[maxn];
  int cur[maxn];
  int p[maxn];
  int num[maxn];
//
  void add(int from, int to, int cap) {
    edges.push_back(Edge(from, to, cap, 0));
    edges.push_back(Edge(to, from, cap, 0));
    m = edges.size();
    G[from].push_back(m - 2);
    G[to].push_back(m - 1);
  }
//
  bool BFS() {
    memset(vis, 0, sizeof(vis));
    queue<int> Q;
    Q.push(t);
    vis[t] = 1;
    d[t] = 0;
    while (!Q.empty()) {
      int x = Q.front();
      Q.pop();
      for (int i = 0; i < G[x].size(); i++) {
        Edge& e = edges[G[x][i] ^ 1];
        if (!vis[e.from] && e.cap > e.flow) {
          vis[e.from] = 1;
          d[e.from] = d[x] + 1;
          Q.push(e.from);
        }
      }
    }
    return vis[s];
  }
//
  void init(int n) {
    this->n = n;
    for (int i = 0; i < n; i++) G[i].clear();
    edges.clear();
  }
//
  int Augment() {
    int x = t, a = inf;
    while (x != s) {
      Edge& e = edges[p[x]];
      a = min(a, e.cap - e.flow);
      x = edges[p[x]].from;
    }
    x = t;
    while (x != s) {
      edges[p[x]].flow += a;
      edges[p[x] ^ 1].flow -= a;
      x = edges[p[x]].from;
    }
    return a;
  }
//
  int maxflow(int s, int t) {
    this->s = s;
    this->t = t;
    int flow = 0;
    BFS();
    memset(num, 0, sizeof(num));
    for (int i = 0; i < n; i++) num[d[i]]++;
    int x = s;
    memset(cur, 0, sizeof(cur));
    while (d[s] < n) {
      if (x == t) {
        flow += Augment();
        x = s;
      }
      int ok = 0;
      for (int i = cur[x]; i < G[x].size(); i++) {
        Edge& e = edges[G[x][i]];
        if (e.cap > e.flow && d[x] == d[e.to] + 1) {
          ok = 1;
          p[e.to] = G[x][i];
          cur[x] = i;
          x = e.to;
          break;
        }
      }
      if (!ok) {
        int m = n - 1;
        for (int i = 0; i < G[x].size(); i++) {
          Edge& e = edges[G[x][i]];
          if (e.cap > e.flow) m = min(m, d[e.to]);
        }
        if (--num[d[x]] == 0) break;
        num[d[x] = m + 1]++;
        cur[x] = 0;
        if (x != s) x = edges[p[x]].from;
      }
    }
    return flow;
  }
} sap;
int n,m;
struct point{
 int x,y;
 int id;
}p[maxn];
int main()
{
    int t;
    scanf("%d", &t);
    while(t--){
        scanf("%d%d", &n, &m);
        sap.init(n+10);
        int x,y;
        point s={inf,inf,0},ed={0,0,0};
        For(i,1,n){
            scanf("%d%d", &x,&y);
            p[i]={x,y,i};
            if(p[i].x>ed.x)ed=p[i];
            if(p[i].x<s.x)s=p[i];
        }
        int u,v,cap;
        For(i,1,m){
            scanf("%d%d%d", &u,&v, &cap);
            sap.add(u,v,cap);
        }
        printf("%d\n",sap.maxflow(s.id,ed.id));
    }
    return 0;
}//

1.1.6----Food HDU - 4292点有限制–拆点,边有限制-容量为限制

在这里插入图片描述
在这里插入图片描述

题意:

与poj3281基本一样。

AC

#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <cstdio>
#define sz(a) (int)(a.size())
#define pb push_back
#define mst(x,a) memset(x,a,sizeof(x))
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define fzhead Edge(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
const int maxn=1e3+10;
const int inf=0x3f3f3f3f;
struct Edge{
    int from, to, cap, flow;
    Edge(){}
    fzhead:fzbody{}
};
struct Dinic{
    int n,m,s,t;
    vector<Edge>edges;
    vector<int>g[maxn];
    bool vis[maxn];
    int d[maxn];
    int cur[maxn];
    void init(int n){
        this->n=n;
        for(int i=0; i<n; i++)g[i].clear();
        edges.clear();
    }
    void add(int from, int to, int cap){
        edges.pb({from,to,cap,0});
        edges.pb({to,from,0,0});
        m=edges.size();
        g[from].pb(m-2);
        g[to].pb(m-1);
    }
    bool bfs(){
        mst(vis,0);mst(d,0);
        queue<int>q;
        q.push(s);
        d[s]=0;
        vis[s]=1;
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=0; i<sz(g[x]); i++){
                Edge&e=edges[g[x][i]];
                if(!vis[e.to]&&e.cap>e.flow){
                    vis[e.to]=1;
                    d[e.to]=d[x]+1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];
    }
    int dfs(int x,int a){
        if(x==t||a==0)return a;
        int flow=0,f;
        for(int &i=cur[x]; i<sz(g[x]); i++){
            Edge&e=edges[g[x][i]];
            if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){
                e.flow+=f;
                edges[g[x][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if(a==0)break;
            }
        }
        return flow;
    }
    int maxflow(int s,int t){
        this->s=s,this->t=t;
        int flow=0;
        while(bfs()){
            mst(cur,0);
            flow+=dfs(s,inf);
        }
        return flow;
    }
} dinic;
int n,f,d;
int a[300],b[300];
int main()
{
    char str[300];
    while(~scanf("%d%d%d", &n, &f, &d)){
        dinic.init(maxn);
        For(i,1,f)scanf("%d",a+i);
        For(i,1,d)scanf("%d", b+i);
        int s=0,t=801;
        For(i,1,f)dinic.add(s,i,a[i]);
        For(i,1,d)dinic.add(600+i,t,b[i]);
        For(i,1,n){
            scanf("%s", str+1);
            for(int j=1; j<=f ;j++){
                if(str[j]=='Y')dinic.add(j,i+200,1);
            }
            dinic.add(i+200,i+400,1);
        }
        For(i,1,n){
            scanf("%s", str+1);
            for(int j=1; j<=d; j++){
                if(str[j]=='Y')dinic.add(i+400,j+600,1);
            }
        }
        printf("%d\n", dinic.maxflow(s,t));
    }
    return 0;
}

1.1.7----Leapin’ Lizards HDU - 2732有限制)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

题意:

  1. 蜥蜴lizard要逃出迷宫,初始时lizard都在柱子上。当lizard跳出柱子,原来的柱子受到磨损。当lizard跳上柱子,不磨损。
  2. 跳的距离为Manhattan距离
  3. 假如在room的边缘,如果从柱子可以跳出迷宫,那么就安全。

思路:

板子。

反思

本题输出有单复数(lizard)

AC

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <cmath>
#include <algorithm>
#include <queue>
#define sz(a) (int)(a.size())
#define pb push_back
#define mst(x,a) memset(x,a,sizeof(x))
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define fzhead Edge(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
const int maxn=400*2+10;
const int inf=0x3f3f3f3f;
struct Edge{
    int from, to, cap, flow;
    Edge(){}
    fzhead:fzbody{}
};
struct Dinic{
    int n,m,s,t;
    vector<Edge>edges;
    vector<int>g[maxn];
    bool vis[maxn];
    int d[maxn];
    int cur[maxn];
    void init(int n){
        this->n=n;
        for(int i=0; i<n; i++)g[i].clear();
        edges.clear();
    }
    void add(int from, int to, int cap){
        edges.pb({from,to,cap,0});
        edges.pb({to,from,0,0});
        m=edges.size();
        g[from].pb(m-2);
        g[to].pb(m-1);
    }
    bool bfs(){
        mst(vis,0);mst(d,0);
        queue<int>q;
        q.push(s);
        d[s]=0;
        vis[s]=1;
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=0; i<sz(g[x]); i++){
                Edge&e=edges[g[x][i]];
                if(!vis[e.to]&&e.cap>e.flow){
                    vis[e.to]=1;
                    d[e.to]=d[x]+1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];
    }
    int dfs(int x,int a){
        if(x==t||a==0)return a;
        int flow=0,f;
        for(int i=0; i<sz(g[x]); i++){
            Edge&e=edges[g[x][i]];
            if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){
                e.flow+=f;
                edges[g[x][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if(a==0)break;
            }
        }
        return flow;
    }
    int maxflow(int s, int t){
        this->s=s,this->t=t;
        int flow=0;
        while(bfs()){
            mst(cur,0);
            flow+=dfs(s,inf);
        }
        return flow;
    }
}dinic;
struct point{
    int x,y;
};
int n,m,d;
int id(int i, int j){
    return (i-1)*m+j;
}
char gap[40][40], lim[40][40];
int Lim[40][40];
int main()
{
    int t,kase=0;
    scanf("%d", &t);
    while(t--){
        int sum=0;
        scanf("%d%d", &n, &d);
        For(i,1,n)scanf("%s",lim[i]+1);
        For(i,1,n)scanf("%s",gap[i]+1);
        m=strlen(lim[1]+1);
        for(int i=1; i<=n; i++){
            for(int j=1; j<=m; j++)Lim[i][j]=lim[i][j]-'0';
        }
        dinic.init(maxn);
        int s=0,ed=801;
        for(int i=1; i<=n; i++){
            for(int j=1; j<=m; j++){
                if(gap[i][j]=='L'){
                    int num=id(i,j);
                    dinic.add(s,num,1);
                    sum++;
                }
            }
        }
        vector<point>pal;
        for(int i=1; i<=n; i++){
            for(int j=1; j<=m; j++){
                if(Lim[i][j]){
                    int num=id(i,j);
                    pal.pb({i,j});//cachid[++cnt]=num;
                    dinic.add(num,num+400,Lim[i][j]);
                    if(i+d>n||i-d<=0||j+d>m||j-d<=0)dinic.add(num+400,ed,inf);//cout<<i<<' '<<j<<' '<<Lim[i][j]<<endl;
                }
            }
        }
       for(int i=0; i<sz(pal); i++){
            for(int j=i+1; j<sz(pal); j++){
                //if(i==j)continue;
                int dis=abs(pal[i].x-pal[j].x)+abs(pal[i].y-pal[j].y);
                int u_num=id(pal[i].x,pal[i].y);
                int v_num=id(pal[j].x,pal[j].y);
                if(dis<=d)dinic.add(v_num+400,u_num,inf),dinic.add(u_num+400,v_num,inf);
            }
       }
      // cout<<sum<<endl;
       int res=sum-dinic.maxflow(s,ed);
       if(res>1)printf("Case #%d: %d lizards were left behind.\n", ++kase,res);
       else if(res==1)printf("Case #%d: %d lizard was left behind.\n", ++kase,res);
       else printf("Case #%d: no lizard was left behind.\n", ++kase);
    }
    return 0;
}

1.1.8----Kakuro Extension HDU - 3338建图,拆点)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(sap莫名wa,我也不懂)

2020-7-28找到问题了。原来没初始化。。。qwq

这位大佬有阐述问题的原因

思路:

看这里大佬的

AC1(dinic)

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <algorithm>
#include <queue>
#include <cmath>
#define sz(a) (int)(a.size())
#define pb push_back
#define mst(x,a) memset(x,a,sizeof(x))
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define fzhead Edge(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
const int maxn=5e4+10;
const int INF=0x3f3f3f3f;
const int maxm=2e5+10;
struct Edge {
	int from, to, cap, flow;
	Edge(int u, int v, int c, int f) : from(u), to(v), cap(c), flow(f) {}
};
//
struct Dinic {
	int n, m, s, t;
	vector<Edge> edges;
	vector<int> G[maxn];
	int d[maxn], cur[maxn];
	bool vis[maxn];
//
	void init(int n) {
		for (int i = 0; i <= n; i++) G[i].clear();
		edges.clear();
	}
//
	void add(int from, int to, int cap) {
		edges.push_back(Edge(from, to, cap, 0));
		edges.push_back(Edge(to, from, 0, 0));
		m = edges.size();
		G[from].push_back(m - 2);
		G[to].push_back(m - 1);
	}
//
	bool BFS() {
		memset(vis, 0, sizeof(vis));
		queue<int> Q;
		Q.push(s);
		d[s] = 0;
		vis[s] = 1;
		while (!Q.empty()) {
			int x = Q.front();
			Q.pop();
			for (int i = 0; i < sz(G[x]); i++) {
				Edge& e = edges[G[x][i]];
				if (!vis[e.to] && e.cap > e.flow) {
					vis[e.to] = 1;
					d[e.to] = d[x] + 1;
					Q.push(e.to);
				}
			}
		}
		return vis[t];
	}
//
	int DFS(int x, int a) {
		if (x == t || a == 0) return a;
		int flow = 0, f;
		for (int& i = cur[x]; i < sz(G[x]); i++) {
			Edge& e = edges[G[x][i]];
			if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0) {
				e.flow += f;
				edges[G[x][i] ^ 1].flow -= f;
				flow += f;
				a -= f;
				if (a == 0) break;
			}
		}
		return flow;
	}
//
	int maxflow(int s, int t) {
		this->s = s;
		this->t = t;
		int flow = 0;
		while (BFS()) {
			memset(cur, 0, sizeof(cur));
			flow += DFS(s, INF);
		}
		return flow;
	}
}dinic;
//
int n,m;
int id(int i, int j){
    return (i-1)*m+j;
}
int getval(char *s){
    int res=0;
    for(int i=1; i<=3; i++){
        res*=10;
        res+=s[i]-'0';
    }
   // cout<<res<<endl;
    return res;
}
struct point{
    int x,y;
    int sta;//0:white 1:black 2:have value
    int up,left;
}p[maxn];
int main()
{
    while(~scanf("%d%d", &n, &m)){
        dinic.init(maxn);mst(p,0);
        char s[20];
        int st=0,ed=2e4+10,dv=1e4;
        For(i,1,n){
            For(j,1,m){
                scanf("%s", s+1);
                int num=id(i,j);
                p[num]={i,j,0,0,0};
                if(s[1]=='.')continue;
                if(s[4]=='X'){p[num].sta=1;continue;}
                if(s[1]!='X')p[num].up=getval(s);
                if(s[5]!='X')p[num].left=getval(s+4);
                p[num].sta=3;
            }
        }
        For(i,1,n){
            For(j,1,m){
                int num=id(i,j);
                if(p[num].sta==3){
                    if(p[num].up){
                        //cout<<num<<endl;
                        vector<int>in;
                        int sum=0;
                        For(k,i+1,n){
                            if(p[id(k,j)].sta==0)sum++,in.pb(id(k,j));
                            else break;
                        }
                        p[num].up-=sum;
                        dinic.add(st,num,p[num].up);
                        for(int k=0; k<sz(in); k++)dinic.add(num,in[k],8);
                    }
                    if(p[num].left){
                        vector<int>in;
                        int sum=0;
                        For(k,j+1,m){
                            if(p[id(i,k)].sta==0)sum++,in.pb(id(i,k));
                            else break;
                        }
                        p[num].left-=sum;
                        dinic.add(num+dv,ed,p[num].left);
                        for(int k=0; k<sz(in); k++)dinic.add(in[k],num+dv,8);
                    }
                }
            }
        }
        //cout<<"ok1"<<endl;
        dinic.maxflow(st,ed);
     //   cout<<"ok2"<<endl;
        vector<Edge>&e=dinic.edges;
        //int &vis=sap.p;
        For(i,1,n){
            For(j,1,m){
                if(p[id(i,j)].sta!=0)printf("_ ");
                else {
                    int num=dinic.G[id(i,j)][1];
                    printf("%d ",e[num].flow+1);
                }
            }
            printf("\n");
        }
    }
    return 0;
}

AC2(isap)

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <algorithm>
#include <queue>
#include <cmath>
#define sz(a) (int)(a.size())
#define pb push_back
#define mst(x,a) memset(x,a,sizeof(x))
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define fzhead Edge(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
const int maxn=5e4+10;
const int inf=0x3f3f3f3f;
const int maxm=2e5+10;
struct Edge {
  int from, to, cap, flow;
  Edge(){}// Edge(int u, int v, int c, int f) : from(u), to(v), cap(c), flow(f) {}
  fzhead:fzbody{}
};
//
bool operator<(const Edge& a, const Edge& b) {
  return a.from < b.from || (a.from == b.from && a.to < b.to);
}
//
struct ISAP {
  int n, m, s, t;
  vector<Edge> edges;
  vector<int> G[maxn];
  bool vis[maxn];
  int d[maxn];
  int cur[maxn];
  int p[maxn];
  int num[maxn];
//
  void add(int from, int to, int cap) {
    edges.push_back(Edge(from, to, cap, 0));
    edges.push_back(Edge(to, from, 0, 0));
    m = edges.size();
    G[from].push_back(m - 2);
    G[to].push_back(m - 1);
  }
//
  bool BFS() {
    for(int i=1;i<=n;i++)d[i]=n;///most important .init!!!!!!!!!!!
    ///这里最好不要用-1或者0x7fffffff等值,否则在统计num的时候可能会出问题
    memset(vis, 0, sizeof(vis));
    queue<int> Q;
    Q.push(t);
    vis[t] = 1;
    d[t] = 0;
    while (!Q.empty()) {
      int x = Q.front();
      Q.pop();
      for (int i = 0; i < sz(G[x]); i++) {
        Edge& e = edges[G[x][i] ^ 1];
        if (!vis[e.from] && e.cap > e.flow) {
          vis[e.from] = 1;
          d[e.from] = d[x] + 1;
          Q.push(e.from);
        }
      }
    }
    return vis[s];
  }
//
  void init(int n) {
    this->n = n;
    for (int i = 0; i < n; i++) G[i].clear();
    edges.clear();
  }
//
  int Augment() {
    int x = t, a = inf;
    while (x != s) {
      Edge& e = edges[p[x]];
      a = min(a, e.cap - e.flow);
      x = edges[p[x]].from;
    }
    x = t;
    while (x != s) {
      edges[p[x]].flow += a;
      edges[p[x] ^ 1].flow -= a;
      x = edges[p[x]].from;
    }
    return a;
  }
//
  int maxflow(int s, int t) {
    this->s = s;
    this->t = t;
    int flow = 0;
    BFS();
    memset(num, 0, sizeof(num));
    for (int i = 0; i < n; i++) num[d[i]]++;
    ///如果d初始为-1等,访问d[-1],d[0x7fffffff]可能会导致未知错误
    int x = s;
    memset(cur, 0, sizeof(cur));
    while (d[s] < n) {
      if (x == t) {
        flow += Augment();
        x = s;
      }
      int ok = 0;
      for (int i = cur[x]; i < sz(G[x]); i++) {
        Edge& e = edges[G[x][i]];
        if (e.cap > e.flow && d[x] == d[e.to] + 1) {
          ok = 1;
          p[e.to] = G[x][i];
          cur[x] = i;
          x = e.to;
          break;
        }
      }
      if (!ok) {
        int m = n - 1;
        for (int i = 0; i < sz(G[x]); i++) {
          Edge& e = edges[G[x][i]];
          if (e.cap > e.flow) m = min(m, d[e.to]);
        }
        if (--num[d[x]] == 0) break;
        num[d[x] = m + 1]++;
        cur[x] = 0;
        if (x != s) x = edges[p[x]].from;
      }
    }
    return flow;
  }
} sap;
int n,m;
int id(int i, int j){
    return (i-1)*m+j;
}
int getval(char *s){
    int res=0;
    for(int i=1; i<=3; i++){
        res*=10;
        res+=s[i]-'0';
    }
   // cout<<res<<endl;
    return res;
}
struct point{
    int x,y;
    int sta;//0:white 1:black 2:have value
    int up,left;
}p[maxn];
int main()
{
    while(~scanf("%d%d", &n, &m)){
        sap.init(maxn);mst(p,0);
        char s[20];
        int st=0,ed=2e4+10,dv=1e4;
        For(i,1,n){
            For(j,1,m){
                scanf("%s", s+1);
                int num=id(i,j);
                p[num]={i,j,0,0,0};
                if(s[1]=='.')continue;
                if(s[4]=='X'){p[num].sta=1;continue;}
                if(s[1]!='X')p[num].up=getval(s);
                if(s[5]!='X')p[num].left=getval(s+4);
                p[num].sta=3;
            }
        }
        For(i,1,n){
            For(j,1,m){
                int num=id(i,j);
                if(p[num].sta==3){
                    if(p[num].up){
                        //cout<<num<<endl;
                        vector<int>in;
                        int sum=0;
                        For(k,i+1,n){
                            if(p[id(k,j)].sta==0)sum++,in.pb(id(k,j));
                            else break;
                        }
                        p[num].up-=sum;
                        sap.add(st,num,p[num].up);
                        for(int k=0; k<sz(in); k++)sap.add(num,in[k],8);
                    }
                    if(p[num].left){
                        vector<int>in;
                        int sum=0;
                        For(k,j+1,m){
                            if(p[id(i,k)].sta==0)sum++,in.pb(id(i,k));
                            else break;
                        }
                        p[num].left-=sum;
                        sap.add(num+dv,ed,p[num].left);
                        for(int k=0; k<sz(in); k++)sap.add(in[k],num+dv,8);
                    }
                }
            }
        }
        //cout<<"ok1"<<endl;
        sap.maxflow(st,ed);
     //   cout<<"ok2"<<endl;
        vector<Edge>&e=sap.edges;
        //int &vis=sap.p;
        For(i,1,n){
            For(j,1,m){
                if(p[id(i,j)].sta!=0)printf("_ ");
                else {
                    int num=sap.G[id(i,j)][1];
                    printf("%d ",e[num].flow+1);
                }
            }
            printf("\n");
        }
    }
    return 0;
}

AC3

另解

Escape HDU - 3605(状态压缩+最大流)

在这里插入图片描述
在这里插入图片描述

题意:

有n个人,每个人对于m个星球有适应性。
问是否可以所有人达成移民。

思路:

直接建图会tle。
m比较少,可以状态压缩。
把状态相同的人归为一类

AC

#include <iostream>
#include <vector>
#include <cstring>
#include <queue>
#include <cstdio>
#include <algorithm>
#define sz(a) ((int)a.size())
#define pb push_back
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define eb emplace_back
#define mst(x,a) memset(x,a,sizeof(x))
#define fzhead EDGE(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
const int N=100+10;
const int maxn=2000;
const int M=0;
const int inf =0x3f3f3f3f;
struct EDGE{
    int from,to,cap,flow;
    EDGE(){}
    fzhead:fzbody{}
};
struct Dinic{
    int n,m,s,t;
    vector<EDGE> edges;
    vector<int> g[maxn];
    bool vis[maxn];
    int d[maxn];
    int cur[maxn];
///cur就是记录当前循环到了哪一条边。
    void init(int n){
        this->n = n;
        for(int i=0; i<n; i++)g[i].clear();
        edges.clear();
    }
    void add(int from, int to, int cap){
       // edges.eb(from,to,cap,0);
        //edges.eb(to,from,0,0);
        edges.pb({from,to,cap,0});
        edges.pb({to,from,0,0});
        ///加边同时,加正向和反向。
        m=edges.size();
        g[from].pb(m-2);
        g[to].pb(m-1);
    }
    bool bfs(){
        mst(vis,0);
        mst(d,0);
        queue<int>q;
        q.push(s);
        d[s]=0;
        vis[s]=1;///源点深度为1.
        while(!q.empty())
        {
            int x=q.front();q.pop();
            for(int i=0; i<sz(g[x]); i++)
            {
                EDGE&e=edges[g[x][i]];
                if(!vis[e.to]&&e.cap>e.flow){
                    vis[e.to]=1;
                    d[e.to]=d[x]+1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];///当汇点的深度不存在时,说明不存在分层图。
    }
    int dfs(int x, int a){
        ///x为当前节点,a为流量。
        if(x==t || a==0)return a;///当已经到达汇点,或者流量不存在时,返回。
        int flow=0,f;
        for(int &i=cur[x]; i<sz(g[x]); i++){
///注意这里的“&”符号,这样i增加同时也能改变cur【x】的值,达到弧优化的目的。
            EDGE& e=edges[g[x][i]];
            if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){///判断并且增广。
                e.flow+=f;///加减
                edges[g[x][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if(a==0)break;
            }

        }
        return flow;
    }
    int maxflow(int s, int t){
        this->s=s,this->t=t;
        int flow=0;
        while(bfs()){
///每一次建立分层图后,都要把cur置为每一个点的第一条边
            mst(cur,0);
        flow+=dfs(s,inf);
        }
        return flow;
    }
} dinic;
int n,m;
int num[2000],lim[20];
int main()
{
    while(~scanf("%d%d", &n, &m)){
        mst(num,0);
        For(i,1,n){
            int tmp=0,x;
            For(j,1,m){
                tmp<<=1;
                scanf("%d", &x);
                tmp+=x;
            }
            num[tmp]++;
        }
        dinic.init(maxn);
        int st=1024+m+1,ed=1024+m+2;
        int cnt=m;
        For(i,1,m)scanf("%d", lim+i),dinic.add(i,ed,lim[i]);
        For(i,0,1024-1){
            if(!num[i])continue;
            cnt++;
            dinic.add(st,cnt,num[i]);
            for(int j=0; j<m; j++){
                if((i>>j)&1)dinic.add(cnt,j+1,num[i]);
            }
        }
        int ans=dinic.maxflow(st,ed);
        if(ans==n)printf("YES\n");//printf("%d\n", ans);
        else printf("NO\n");
    }
    return 0;
}

1.2最大瘤变式–>MincostMaxflow

1.2.1----Going Home POJ - 2195(McMf模板)

在这里插入图片描述
在这里插入图片描述

题意:

有cnt1个房子,cnt2个人。
人要进到房子里,问怎样走,可以使人的路程和最小。

思路:

裸的最小费用最大流

  1. 先建点,距离是哈夫曼距离(横坐标的绝对值之差,加上纵坐标的绝对值之差的绝对值)
  2. 把每个人和房子连边。
  3. 之后直接跑mxmf即可。

AC

#include <iostream>
#include <queue>
#include <cstring>
#include <string>
#include <vector>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define pb push_back
#define sz(a) (int)(a.size())
#define mst(x,a) memset(x,a,sizeof(x))
#define fzhead EDGE(int u, int v, int c, int f, int w)
#define fzbody from(u), to(v), cap(c), flow(f), cost(w)
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn=1003;
const int maxm=40004;
struct EDGE
{
    int from,to,cap,flow,cost;
    EDGE(){}
    fzhead:fzbody{}
};
struct MXMF
{
    int n,m;
    vector<EDGE> edges;
    vector<int>g[maxn];
    int vis[maxn];//判断是否在队中
    int d[maxn];//Bellman-Ford
    int p[maxn];//上一条弧
    int a[maxn];//可改进量
    //
    void init(int n)
    {
        this->n=n;
        for(int i=0; i<n; i++)g[i].clear();
        edges.clear();
    }
    //
    void add(int from, int to, int cap, int cost)
    {
        edges.pb(EDGE(from,to,cap,0,cost));
        edges.pb(EDGE(to,from,0,0,-cost));
        m=edges.size();
        g[from].pb(m-2);
        g[to].pb(m-1);
    }
    //
    bool BellmanFord(int s, int t, int&flow, ll &cost)
    {
        for(int i=0; i<n; i++)d[i]=INF;
        mst(vis,0);
        d[s]=0;vis[s]=1;p[s]=0;a[s]=INF;
        //
        queue<int>q;
        q.push(s);
        while(!q.empty())
        {
            int u=q.front();q.pop();
            vis[u]=0;
            for(int i=0; i<sz(g[u]); i++)
            {
                EDGE&e=edges[g[u][i]];
                if(e.cap>e.flow&&d[e.to]>d[u]+e.cost)
                {
                    d[e.to]=d[u]+e.cost;
                    p[e.to]=g[u][i];
                    a[e.to]=min(a[u],e.cap-e.flow);
                    if(!vis[e.to])
                    {
                        q.push(e.to);
                        vis[e.to]=1;
                    }
                }
            }
        }
        if(d[t]==INF)return false;
        flow+=a[t];
        cost+=(ll)d[t]*(ll)a[t];
        for(int u=t; u!=s; u=edges[p[u]].from)
        {
            edges[p[u]].flow+=a[t];
            edges[p[u]^1].flow-=a[t];
        }
        return true;
    }
    int MincostMaxflow(int s, int t, ll&cost)
    {
        int flow=0;cost=0;
        while(BellmanFord(s,t,flow,cost));
        return flow;
    }
}mxmf;
struct point
{
    int x,y;
}house[maxn],men[maxn];
int main()
{
    int n,m;
    char s[200];
    while(scanf("%d%d", &n,&m)&&(n&&m))
    {
        mxmf.init(maxn);
        int cnt1,cnt2;
        cnt1=cnt2=0;//cnt1-house, cnt2-men
        for(int i=0; i<n; i++)
        {
            scanf("%s", s);
            for(int j=0; j<m; j++)
            {
                if(s[j]=='H')house[++cnt1].x=i,house[cnt1].y=j;
                if(s[j]=='m')men[++cnt2].x=i,men[cnt2].y=j;
            }
        }
        int st=0,ed=cnt1+cnt2+1;
        for(int i=1; i<=cnt2; i++)
        {
            for(int j=1; j<=cnt1; j++)
            {
                int w=abs(men[i].x-house[j].x)+abs(men[i].y-house[j].y);
                mxmf.add(i,cnt2+j,1,w);
            }
        }
        for(int i=1; i<=cnt2; i++)
        {
            mxmf.add(st,i,1,0);
            mxmf.add(cnt2+i,ed,1,0);
        }
        ll cost=0,flow=0;
        mxmf.MincostMaxflow(st,ed,cost);
        printf("%lld\n",cost);
    }
    return 0;
}

1.2.2----Minimum Cost POJ - 2516(mcmf,跑k次)

在这里插入图片描述
在这里插入图片描述

题意:

有n个批发点supply place, 和m个shopkeeper店主。
而且有k种产品。(运费不同)
问怎样分配运费,可以使得总费用最小。

思路:

  1. 直接建图的话,50x50 x 50x50个点,有1e6,所以考虑跑k次

反思

建点和连边时,最好画一个图,避免连错。(连边时,思路可以更清晰)

AC

#include <iostream>
#include <queue>
#include <cstring>
#include <string>
#include <vector>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define pb push_back
#define sz(a) (int)(a.size())
#define mst(x,a) memset(x,a,sizeof(x))
#define fzhead Edge(int u, int v, int c, int f, int w)
#define fzbody from(u), to(v), cap(c), flow(f), cost(w)
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn=3000;
const int maxm=400004;
struct Edge
{
    int from, to, cap, flow, cost;
    Edge(){}
    fzhead:fzbody{}
};
struct MCMF
{
    int n,m;
    vector<Edge>edges;
    vector<int> g[maxn];
    int vis[maxn];
    int d[maxn];
    int p[maxn];
    int a[maxn];
    //
    void init(int n)
    {
        this->n=n;
        for(int i=0; i<n; i++)g[i].clear();
        edges.clear();
    }
    //
    void add(int from, int to, int cap, int cost)
    {
        edges.pb(Edge(from,to,cap,0,cost));
        edges.pb(Edge(to,from,0,0,-cost));
        m=edges.size();
        g[from].pb(m-2);
        g[to].pb(m-1);
    }
    //
    bool BellmanFord(int s,int t, int&flow, ll&cost)
    {
        for(int i=0 ; i<n; i++)d[i]=INF;
        mst(vis,0);
        d[s]=0;vis[s]=1;p[s]=0;a[s]=INF;
        //
        queue<int>q;
        q.push(s);
        while(!q.empty())
        {
            int u=q.front();q.pop();
            vis[u]=0;
            for(int i=0; i<sz(g[u]); i++)
            {
                Edge& e=edges[g[u][i]];
                if(e.cap>e.flow&& d[e.to]>d[u]+e.cost)
                {
                    d[e.to]=d[u]+e.cost;
                    p[e.to]=g[u][i];
                    a[e.to]=min(a[u],e.cap-e.flow);
                    if(!vis[e.to])
                    {
                        q.push(e.to);
                        vis[e.to]=1;
                    }
                }
            }
        }
        if(d[t]==INF)return false;
        flow+=a[t];
        cost+=(ll)d[t]*(ll)a[t];
        for(int u=t; u!=s; u=edges[p[u]].from)
        {
            edges[p[u]].flow+=a[t];
            edges[p[u]^1].flow-=a[t];
        }
        return true;
    }
    int MincostMaxflow(int s,int t, ll& cost)
    {
        int flow=0;cost=0;
        while(BellmanFord(s,t,flow,cost));
        return flow;
    }
}mcmf;
int n,m,k;
int need[100][100],have[100][100];
int main()
{
    while(scanf("%d%d%d", &n,&m,&k)&&n&&m&&k)
    {
        mcmf.init(maxn);
        int flag=1,s=0,e=n+m+1;
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=k; j++)scanf("%d", need[i]+j);
        }
        for(int i=1; i<=m; i++)
        {
            for(int j=1; j<=k; j++)scanf("%d", have[i]+j);
        }
        ll cost,ans=0,flow;
        for(int i=1; i<=k; i++)
        {
            mcmf.init(maxn);
            for(int p=1; p<=n; p++)
            {
                for(int q=1; q<=m; q++)
                {
                    int w;
                    scanf("%d", &w);
                    mcmf.add(q,m+p,INF,w);
                }
            }
            if(!flag)continue;
            for(int p=1; p<=m; p++)mcmf.add(s,p,have[p][i],0);
            ll sum=0;
            for(int p=1; p<=n; p++)
            {
                mcmf.add(p+m,e,need[p][i],0);
                sum+=need[p][i];
            }
            flow=cost=0;
            flow=mcmf.MincostMaxflow(s,e,cost);
         //   cout<<"k== "<<k<<' '<<sum<<' '<<cost<<endl;
            if(flow!=sum)flag=0;
            else ans+=cost;
        }
        if(flag)printf("%lld\n", ans);
        else printf("-1\n");
    }
    return 0;
}

1.3最大瘤变式–>最小鸽

1.3.1----Control HDU - 4289(最小割&&割点,加拆点)

在这里插入图片描述
在这里插入图片描述

题意:

有一个不法分子,会从 s s s出发到 d e de de.为了抓到他,要在城市设置sa(特工),问最少需要设置几个特工。

思路&&反思

问题就是最小割。增广后,不能再增广。

  1. 最小割一般有联系的边,设置为 I N F INF INF
  2. 一个点的花费,就拆点。
  3. 注意拆点后 首尾相连.
    在这里插入图片描述图片来自传送门

AC

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <algorithm>
#include <queue>
#define mst(x,a) memset(x,a,sizeof(x))
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define pb push_back
#define sz(a) (int)(a.size())
#define fzhead Edge(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
const int maxm=400+10+4e4+10;
const int maxn=400+10;
const int inf=0x3f3f3f3f;
struct Edge{
    int from, to, cap, flow;
    Edge(){}
    fzhead:fzbody{}
};
struct Dinic{
    int n,m,s,t;
    vector<Edge>edges;
    vector<int>g[maxn];
    int d[maxn];
    bool vis[maxn];
    int cur[maxn];
    void init(int n){
        this->n=n;
        for(int i=0; i<n; i++)g[i].clear();
        edges.clear();
    }
    void add(int from, int to, int cap){
        edges.pb({from,to,cap,0});
        edges.pb({to,from,0,0});
        m=edges.size();
        g[from].pb(m-2);
        g[to].pb(m-1);
    }
    bool bfs(){
        mst(vis,0);mst(d,0);
        queue<int>q;
        q.push(s);
        vis[s]=1;
        d[s]=0;
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=0; i<sz(g[x]); i++){
                Edge&e=edges[g[x][i]];
                if(!vis[e.to]&&e.cap>e.flow){
                    vis[e.to]=1;
                    d[e.to]=d[x]+1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];
    }
    int dfs(int x, int a){
        if(x==t||a==0)return a;
        int flow=0,f;
        for(int &i=cur[x]; i<sz(g[x]); i++){
            Edge&e=edges[g[x][i]];
            if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){
                e.flow+=f;
                edges[g[x][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if(a==0)break;
            }
        }
        return flow;
    }
    int maxflow(int s, int t){
        this->s=s,this->t=t;
        int flow=0;
        while(bfs()){
            mst(cur,0);
            flow+=dfs(s,inf);
        }
        return flow;
    }
} dinic;
int n,m,s,e;
int main()
{
    while(~scanf("%d%d", &n, &m)){
        dinic.init(maxn);
        scanf("%d%d", &s, &e);
        int w,u,v;
        int st=0,ed=401;
        dinic.add(st,s,inf);
        dinic.add(e+n,ed,inf);
        For(i,1,n){
            scanf("%d",&w);
            dinic.add(i,i+n,w);
            dinic.add(n+i,i,w);
        }
        For(i,1,m){
            scanf("%d%d", &u,&v);
            dinic.add(u+n,v,inf);
            dinic.add(v+n,u,inf);
        }
        printf("%d\n",dinic.maxflow(st,ed));
    }
    return 0;
}

Sabotage UVA - 10480割边

在这里插入图片描述
在这里插入图片描述

题意:

给你一个网络图。起点和终点,要求你割掉最小费用的边,使s和d不联通。

思路:

  1. 跑一遍最大流,
  2. 残余网络里,把与s联通的点找出来,标记为1。(剩下的点就与t联通
  3. 那么答案就是:遍历输入的每一条边,假如两点vis不同,那么就输出。

AC

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值