网络流

图论-网络流①-什么是网络流 图论-网络流 参考文献: https://www.cnblogs.com/DuskOB/p/11216861.html https://blog.youkuaiyun.com/yjr3426619/article/details/82808303 https://blog.youkuaiyun.com/lym940928/article/details/90209172 https://baike.baidu.com... 阅读详情


上连接:

初期,比较简单

http://www.cnblogs.com/exponent/archive/2011/11/11/2245324.html



poj 1459

网络流模板题



模板来自kuangbin




#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
using namespace std;
const int MAXN=110;
const int INF=0x7fffffff;
int map[MAXN][MAXN],path[MAXN],flow[MAXN],start,end;
int n;//点的个数
queue<int>q;
int bfs()
{
    int i,t;
    while(!q.empty()) q.pop();//清空队列
    memset(path,-1,sizeof(path));
    path[start]=0;
    flow[start]=INF;
    q.push(start);
    while(!q.empty())
    {
        t=q.front();
        q.pop();
        if(t==end)  break;
        for(i=0;i<=n;i++)
        {
            if(i!=start&&path[i]==-1&&map[t][i])
            {
                flow[i]=flow[t]<map[t][i]?flow[t]:map[t][i];
                q.push(i);
                path[i]=t;
            }    
        }   
           
    }  
    if(path[end]==-1)  return -1;
        return flow[n];     
}       
int Edmonds_Karp()
{
    int max_flow=0,step,now,pre;
    while((step=bfs())!=-1)
    {
        max_flow+=step;
        now=end;
        while(now!=start)
        {
            pre=path[now];
            map[pre][now]-=step;
            map[now][pre]+=step;
            now=pre;
        }    
    }  
    return max_flow;  
}    
int main()
{
    int i,u,v,z,np,nc,m;
    while(scanf("%d%d%d%d",&n,&np,&nc,&m)!=EOF)
    {
        memset(map,0,sizeof(map));
        while(m--)
        {
            while(getchar()!='(');
            scanf("%d,%d)%d",&u,&v,&z);
            u++;v++;
            map[u][v]=z;
        }    
        while(np--)
        {
            while(getchar()!='(');
            scanf("%d)%d",&u,&z);
            u++;
            map[0][u]=z;
        }  
        while(nc--)
        {
            while(getchar()!='(');
            scanf("%d)%d",&u,&z);
            u++;
            map[u][n+1]=z;
        }  
        n++;
        start=0;end=n;
        printf("%d\n",Edmonds_Karp());    
    }    
    return 0;
}

poj 1698


这个是建图

题意:有N部电影,分别可以在一个星期的几天拍摄,并可以拍W个星期,Alice可以有D个星期拍这部电影,一天只能拍一部电影。问Alice能否拍完所有电影。


让0作为源点,377(377不会再星期+日期中出现的)作为汇点


首先0-n之间的每一个都要连一条容量为D的边(n为每个电影上)

接着从n-(i*7+j)//第i星期第j天之间连一条容量为1的边

最后从每星期的每一天到汇点377都连一条容量为1的边


sum+=D;

跑一遍DINIC,判断sum与最大流量是否相等即可。

#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")

using namespace std;
#define   MAX           100005
#define   MAXN          10000005
#define   maxnode       500005
#define   sigma_size    30
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   lrt           rt<<1
#define   rrt           rt<<1|1
#define   middle        int m=(r+l)>>1
#define   LL            long long
#define   ull           unsigned long long
#define   mem(x,v)      memset(x,v,sizeof(x))
#define   lowbit(x)     (x&-x)
#define   pii           pair<int,int>
#define   bits(a)       __builtin_popcount(a)
#define   mk            make_pair

const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const LL     INFF  = 1e18;
const double pi    = 3.141592653589793;
const double inf   = 1e18;
const double eps   = 1e-8;
const int    mod   = 100007;
const ull    mx    = 133333331;

/*****************************************************/
inline void RI(int &x) {
      char c;
      while((c=getchar())<'0' || c>'9');
      x=c-'0';
      while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
 }
/*****************************************************/

int N, NP, NC, M;
struct Edge
{
    int u, v, cap;
    Edge() {}
    Edge(int u, int v, int cap): u(u), v(v), cap(cap) {}
} es[350 * 350];
int R, S, T;
vector<int> tab[350+40]; // 边集
int dis[350+40];
int current[350+40];
void addedge(int u, int v, int cap)
{
    tab[u].push_back(R);
    es[R++] = Edge(u, v, cap); // 正向边
    tab[v].push_back(R);
    es[R++] = Edge(v, u, 0); // 反向边容量为0
    // 正向边下标通过异或就得到反向边下标, 2 ^ 1 == 3 ; 3 ^ 1 == 2
}
int BFS()
{
    queue<int> q;
    q.push(S);
    memset(dis, 0x3f, sizeof(dis));
    dis[S] = 0;
    while (!q.empty())
    {
        int h = q.front();
        q.pop();
        for (int i = 0; i < tab[h].size(); i++)
        {
            Edge &e = es[tab[h][i]];
            if (e.cap > 0 && dis[e.v] == 0x3f3f3f3f)
            {
                dis[e.v] = dis[h] + 1;
                q.push(e.v);
            }
        }
    }
    return dis[T] < 0x3f3f3f3f; // 返回是否能够到达汇点
}
int dinic(int x, int maxflow)
{
    if (x == T)
        return maxflow;
    // i = current[x] 当前弧优化
    for (int i = current[x]; i < tab[x].size(); i++)
    {
        current[x] = i;
        Edge &e = es[tab[x][i]];
        if (dis[e.v] == dis[x] + 1 && e.cap > 0)
        {
            int flow = dinic(e.v, min(maxflow, e.cap));
            if (flow)
            {
                e.cap -= flow; // 正向边流量降低
                es[tab[x][i] ^ 1].cap += flow; // 反向边流量增加
                return flow;
            }
        }
    }
    return 0; // 找不到增广路 退出
}
int DINIC()
{
    int ans = 0;

    while (BFS()) // 建立分层图
    {
        int flow;
        memset(current, 0, sizeof(current)); // BFS后应当清空当前弧数组
        while (flow = dinic(S, 0x3f3f3f3f)) // 一次BFS可以进行多次增广
            ans += flow;
    }
    return ans;
}
int f[60][10];
void ori(){
    R=0;
    memset(f,0,sizeof(f));
    for(int i=0;i<350+40;i++)
        tab[i].clear();


}

int main(){
    int t,n,W,D,sum,flag;
    scanf("%d",&t);
    while(t--){
            ori();
            sum=0;
            flag=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=7;j++)scanf("%d",&f[i][j]);
            scanf("%d%d",&D,&W);
            sum+=D;
            if(W>flag)flag=W;
            addedge(0,i,D);
            for(int p=1;p<=W;p++)for(int q=1;q<=7;q++)if(f[i][q])addedge(i,7*p+q+n,1);


        }
        S=0;
        for(int i=1;i<=flag;i++)for(int j=1;j<=7;j++)addedge(7*i+j+n,377,1);
        T=377;
        int re=DINIC();
        if(sum==re)printf("Yes\n");
        else printf("No\n");

    }

}


poj 2112

额,这个题真是做的人心好累


题意:有K台挤奶机(编号1~K),C头奶牛(编号K+1~K+C),给出各点之间距离。现在要让C头奶牛到挤奶机去挤奶,每台挤奶机只能处理M头奶牛,求使所走路程最远的奶牛的路程最短的方案。

构图:先Floyd求所有点对之间最短路,二分最短长度,若奶牛与挤奶机之间的距离大于mid则不连边,否则连容量为1的边。源向挤奶机连容量M的边,奶牛向汇连容量1的边,用最大流判可行性。


问了问逊哥,说求最长路径的最短值,典型的二分特政......



然后在写的过程中也是各种错,我觉得都是些可以避免的错......像把K和C的含义搞反,像少写了<号,还是素养的问题,你自己多反思......


然后近段时间有进步吧,不过写题还是很慢,算了只能慢慢写了,上代码,代码比较不是很好看,用的是DINIC,速度还行......



#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")

using namespace std;
#define   MAX           100005
#define   MAXN          10000005
#define   maxnode       500005
#define   sigma_size    30
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   lrt           rt<<1
#define   rrt           rt<<1|1
#define   middle        int m=(r+l)>>1
#define   LL            long long
#define   ull           unsigned long long
#define   mem(x,v)      memset(x,v,sizeof(x))
#define   lowbit(x)     (x&-x)
#define   pii           pair<int,int>
#define   bits(a)       __builtin_popcount(a)
#define   mk            make_pair

const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const LL     INFF  = 1e18;
const double pi    = 3.141592653589793;
const double inf   = 1e18;
const double eps   = 1e-8;
const int    mod   = 100007;
const ull    mx    = 133333331;

/*****************************************************/
inline void RI(int &x) {
      char c;
      while((c=getchar())<'0' || c>'9');
      x=c-'0';
      while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
 }
/*****************************************************/

int N, NP, NC, M;
int len[230*230+10];
struct Edge
{
    int u, v, cap;
    Edge() {}
    Edge(int u, int v, int cap): u(u), v(v), cap(cap) {}
} es[400*400];
int R, S, T;
vector<int> tab[350+40]; // 边集
int dis[350+40];
int current[350+40];
void addedge(int u, int v, int cap)
{
    tab[u].push_back(R);
    es[R++] = Edge(u, v, cap); // 正向边
    tab[v].push_back(R);
    es[R++] = Edge(v, u, 0); // 反向边容量为0
    // 正向边下标通过异或就得到反向边下标, 2 ^ 1 == 3 ; 3 ^ 1 == 2
}
int BFS()
{
    queue<int> q;
    q.push(S);
    memset(dis, 0x3f, sizeof(dis));
    dis[S] = 0;
    while (!q.empty())
    {
        int h = q.front();
        q.pop();
        for (int i = 0; i < tab[h].size(); i++)
        {
            Edge &e = es[tab[h][i]];
            if (e.cap > 0 && dis[e.v] == 0x3f3f3f3f)
            {
                dis[e.v] = dis[h] + 1;
                q.push(e.v);
            }
        }
    }
    return dis[T] < 0x3f3f3f3f; // 返回是否能够到达汇点
}
int dinic(int x, int maxflow)
{
    if (x == T)
        return maxflow;
    // i = current[x] 当前弧优化
    for (int i = current[x]; i < tab[x].size(); i++)
    {
        current[x] = i;
        Edge &e = es[tab[x][i]];
        if (dis[e.v] == dis[x] + 1 && e.cap > 0)
        {
            int flow = dinic(e.v, min(maxflow, e.cap));
            if (flow)
            {
                e.cap -= flow; // 正向边流量降低
                es[tab[x][i] ^ 1].cap += flow; // 反向边流量增加
                return flow;
            }
        }
    }
    return 0; // 找不到增广路 退出
}
int DINIC()
{
    int ans = 0;

    while (BFS()) // 建立分层图
    {
        int flow;
        memset(current, 0, sizeof(current)); // BFS后应当清空当前弧数组
        while (flow = dinic(S, 0x3f3f3f3f)) // 一次BFS可以进行多次增广
            ans += flow;
    }
    return ans;
}
//int f[60][10];
int Map[300][300];
int cnt;
void ori(){
    //memset(Map,INF,sizeof(Map));
    R=0;
    for(int i=0;i<350+40;i++)
        tab[i].clear();


}
int k,c,m;
void floyd()
{
  int i,j,q;
  for( q=1;q<=k+c;++q )
    for( i=1;i<=k+c;++i )
      for( j=1;j<=k+c;++j )
        Map[i][j]=min(Map[i][j],Map[i][q]+Map[q][j]);
}
bool cmp(int a,int b){
    return a<b;
}
bool judge(int M){//c cow k machine
    ori();
    R=0;
    for(int i=0;i<350+40;i++)tab[i].clear();
    for(int i=1;i<=k;i++)addedge(0,i,m);
    for(int i=k+1;i<=k+c;i++)for(int j=1;j<=k;j++)if(Map[i][j]<=M)addedge(j,i,1);//from machine to cow
    for(int i=k+1;i<=k+c;i++)addedge(i,377,1);//from cow to T
    S=0;T=377;
    int re=DINIC();
    if(re<c)return false;
    return true;


}
int main(){

    while(~scanf("%d%d%d",&k,&c,&m)){
            cnt=0;
            memset(Map,INF,sizeof(INF));
        for(int i=1;i<=k+c;i++)for(int j=1;j<=k+c;j++){
                scanf("%d",&Map[i][j]);
                if(i!=j&&Map[i][j]==0)Map[i][j]=INF;
                Map[j][i]=Map[i][j];
                }

        floyd();
        for(int i=1;i<=k+c;i++)for(int j=1;j<=k+c;j++){if(i==j)continue;len[cnt++]=Map[i][j];}
        sort(len,len+cnt,cmp);
        int L=0,R=cnt-1;
        while(L<=R){
            int Mid=(L+R)/2;
            int X=len[Mid];
            if(judge(X))R=Mid-1;
            else L=Mid+1;
        }
        printf("%d\n",len[L]);
    }

}


poj 2455


题意:有N个农场,P条无向路连接。要从1到N不重复走T条路,求所经过的直接连接两个区域的道路中最长道路中的最小值.

构图:源点向1连容量T的边。二分最小长度,(最长道路的最小值)长度超过mid的边容量为0,否则为1,用最大流判可行性。

注意:1.该题有重边,切忌用邻接矩阵删除重边(重边要用邻接表来处理以保留)。

2.无向图在addedge中要进行处理(处理方式见代码)。

在addedge()中,有一部分要改一下


void addedge(int u, int v, int cap)
{
    tab[u].push_back(R);
    es[R++] = Edge(u, v, cap); // 正向边
    tab[v].push_back(R);
    es[R++] = Edge(v, u, 0); // 反向边容量为0
    // 正向边下标通过异或就得到反向边下标, 2 ^ 1 == 3 ; 3 ^ 1 == 2
}

改为:

void addedge(int u, int v, int cap)
{
    tab[u].push_back(R);
    es[R++] = Edge(u, v, cap); // 正向边
    tab[v].push_back(R);
    es[R++] = Edge(v, u, cap); // 反向边容量为cap 对无向图来说
    // 正向边下标通过异或就得到反向边下标, 2 ^ 1 == 3 ; 3 ^ 1 == 2
}


刚开始就是这个地方没改,一直WA(最开始是RE,就数组一直在扩......)

以后要随机应变


上代码


#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")

using namespace std;
#define   MAX           100005
#define   MAXN          10000005
#define   maxnode       500005
#define   sigma_size    30
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   lrt           rt<<1
#define   rrt           rt<<1|1
#define   middle        int m=(r+l)>>1
#define   LL            long long
#define   ull           unsigned long long
#define   mem(x,v)      memset(x,v,sizeof(x))
#define   lowbit(x)     (x&-x)
#define   pii           pair<int,int>
#define   bits(a)       __builtin_popcount(a)
#define   mk            make_pair

const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const LL     INFF  = 1e18;
const double pi    = 3.141592653589793;
const double inf   = 1e18;
const double eps   = 1e-8;
const int    mod   = 100007;
const ull    mx    = 133333331;

/*****************************************************/
inline void RI(int &x) {
      char c;
      while((c=getchar())<'0' || c>'9');
      x=c-'0';
      while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
 }
/*****************************************************/

typedef struct EdgeTmp{
    int f,t,cap;
}EdgeTmp;
EdgeTmp Map[80100];
struct Edge
{
    int u, v, cap;
    Edge() {}
    Edge(int u, int v, int cap): u(u), v(v), cap(cap) {}
} es[80100];
int R, S, T;
vector<int> tab[80100]; // 边集
int dis[80100];
int current[80100];
void addedge(int u, int v, int cap)
{
    tab[u].push_back(R);
    es[R++] = Edge(u, v, cap); // 正向边
    tab[v].push_back(R);
    es[R++] = Edge(v, u, cap); // 反向边容量为cap
    // 正向边下标通过异或就得到反向边下标, 2 ^ 1 == 3 ; 3 ^ 1 == 2
}
int BFS()
{
    queue<int> q;
    q.push(S);
    memset(dis, 0x3f, sizeof(dis));
    dis[S] = 0;
    while (!q.empty())
    {
        int h = q.front();
        q.pop();
        for (int i = 0; i < tab[h].size(); i++)
        {
            Edge &e = es[tab[h][i]];
            if (e.cap > 0 && dis[e.v] == 0x3f3f3f3f)
            {
                dis[e.v] = dis[h] + 1;
                q.push(e.v);
            }
        }
    }
    return dis[T] < 0x3f3f3f3f; // 返回是否能够到达汇点
}
int dinic(int x, int maxflow)
{
    if (x == T)
        return maxflow;
    // i = current[x] 当前弧优化
    for (int i = current[x]; i < tab[x].size(); i++)
    {
        current[x] = i;
        Edge &e = es[tab[x][i]];
        if (dis[e.v] == dis[x] + 1 && e.cap > 0)
        {
            int flow = dinic(e.v, min(maxflow, e.cap));
            if (flow)
            {
                e.cap -= flow; // 正向边流量降低
                es[tab[x][i] ^ 1].cap += flow; // 反向边流量增加
                return flow;
            }
        }
    }
    return 0; // 找不到增广路 退出
}
int DINIC()
{
    int ans = 0;

    while (BFS()) // 建立分层图
    {
        int flow;
        memset(current, 0, sizeof(current)); // BFS后应当清空当前弧数组
        while (flow = dinic(S, 0x3f3f3f3f)) // 一次BFS可以进行多次增广
            ans += flow;
    }
    return ans;
}

void ori(){

    R=0;
    for(int i=0;i<80100;i++)
        tab[i].clear();


}

int cnt;
int n,k,Tt;
bool judge(int M){
    ori();
    S=0;
    T=n;
    addedge(0,1,Tt);
    for(int i=0;i<cnt;i++)if(Map[i].cap<=M)addedge(Map[i].f,Map[i].t,1);


    int re=DINIC();
    if(re<Tt)return false;
    return true;


}
int main(){

    while(~scanf("%d%d%d",&n,&k,&Tt)){

            int L=INF,R=0;
            cnt=0;
            for(int i=1;i<=k;i++){
                int a,b,l;
                scanf("%d%d%d",&a,&b,&l);
                EdgeTmp tmp;
                tmp.f=a,tmp.t=b,tmp.cap=l;
                Map[cnt++]=tmp;
                if(l<L)L=l;
                if(l>R)R=l;
                }
            while(L<=R){
                int Mid=(L+R)/2;
                if(judge(Mid))R=Mid-1;
                else L=Mid+1;
            }
            printf("%d\n",L);

    }

}

poj 1149



题意和题解我已经无心去写了......


然后这个题一直在RE,然后我就把边表使劲开大,使劲开大,然后他妈的的MLE,然后我就不知道怎么办了,总想着是不是我思路错了,就一直纠结纠结......

后来果断问马神,然后他做了一发,然后他和我说是我数组开小了,我还说不可能(因为边表确实开到了最大)

然后他一来,帮我把customer相关量开到了1500,然后就他妈的AC了


我去,题目明明说的是customer不会过100,不会过100,去他妹的题目,真坑人


上代码


#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")

using namespace std;
#define   MAX           100005
#define   MAXN          10000005
#define   maxnode       500005
#define   sigma_size    30
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   lrt           rt<<1
#define   rrt           rt<<1|1
#define   middle        int m=(r+l)>>1
#define   LL            long long
#define   ull           unsigned long long
#define   mem(x,v)      memset(x,v,sizeof(x))
#define   lowbit(x)     (x&-x)
#define   pii           pair<int,int>
#define   bits(a)       __builtin_popcount(a)
#define   mk            make_pair

const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const LL     INFF  = 1e18;
const double pi    = 3.141592653589793;
const double inf   = 1e18;
const double eps   = 1e-8;
const int    mod   = 100007;
const ull    mx    = 133333331;
const int cs = 100100 ;

/*****************************************************/
inline void RI(int &x) {
      char c;
      while((c=getchar())<'0' || c>'9');
      x=c-'0';
      while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
 }
/*****************************************************/
int M,N;
int pig[1050],numA[1500],numB[1500],last[1500];
struct Edge
{
    int u, v, cap;
    Edge() {}
    Edge(int u, int v, int cap): u(u), v(v), cap(cap) {}
} es[cs];
int R, S, T;
vector<int> tab[cs]; // 边集
int dis[cs];
int current[cs];
void addedge(int u, int v, int cap)
{
    tab[u].push_back(R);
    es[R++] = Edge(u, v, cap); // 正向边
    tab[v].push_back(R);
    es[R++] = Edge(v, u, 0); // 反向边容量为0
    // 正向边下标通过异或就得到反向边下标, 2 ^ 1 == 3 ; 3 ^ 1 == 2
}
int BFS()
{
    queue<int> q;
    q.push(S);
    memset(dis, 0x3f, sizeof(dis));
    dis[S] = 0;
    while (!q.empty())
    {
        int h = q.front();
        q.pop();
        for (int i = 0; i < tab[h].size(); i++)
        {
            Edge &e = es[tab[h][i]];
            if (e.cap > 0 && dis[e.v] == 0x3f3f3f3f)
            {
                dis[e.v] = dis[h] + 1;
                q.push(e.v);
            }
        }
    }
    return dis[T] < 0x3f3f3f3f; // 返回是否能够到达汇点
}
int dinic(int x, int maxflow)
{
    if (x == T)
        return maxflow;
    // i = current[x] 当前弧优化
    for (int i = current[x]; i < tab[x].size(); i++)
    {
        current[x] = i;
        Edge &e = es[tab[x][i]];
        if (dis[e.v] == dis[x] + 1 && e.cap > 0)
        {
            int flow = dinic(e.v, min(maxflow, e.cap));
            if (flow)
            {
                e.cap -= flow; // 正向边流量降低
                es[tab[x][i] ^ 1].cap += flow; // 反向边流量增加
                return flow;
            }
        }
    }
    return 0; // 找不到增广路 退出
}
int DINIC()
{
    int ans = 0;

    while (BFS()) // 建立分层图
    {
        int flow;
        memset(current, 0, sizeof(current)); // BFS后应当清空当前弧数组
        while (flow = dinic(S, 0x3f3f3f3f)) // 一次BFS可以进行多次增广
            ans += flow;
    }
    return ans;
}

void ori(){

    R=0,S=0,T=N+1;
    for(int i=0;i<cs;i++)tab[i].clear();
    memset(last,-1,sizeof(last));


}



int main(){
    // M pig N customer
    while(~scanf("%d%d",&M,&N)){
            ori();
            for(int i=1;i<=M;i++)scanf("%d",&pig[i]);
            for(int i=1;i<=N;i++){
                scanf("%d",&numA[i]);

                for(int j=0;j<numA[i];j++){
                        int tmp;
                    scanf("%d",&tmp);
                    if(last[tmp]==-1)addedge(S,i,pig[tmp]);
                    else addedge(last[tmp],i,INF);
                    last[tmp]=i;

                }
                scanf("%d",&numB[i]);
                addedge(i,T,numB[i]);
            }

            int re=DINIC();
            printf("%d\n",re);


    }
}


然后我又get到一个新技能,以后RE不要怂,所有的数组都开大,不管题目怎么说,开大数组,开大数组,不要怂......



poj 2135


最小费用流模板题,学学费用流怎么建边

最小费用流是用spfa来写的,反正就难在建图,图建出来了就套模板......

我这里直接用了某人的模板

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <queue>
#define V 10100
#define E 1000100
#define inf 99999999
using namespace std;
int vis[V];
int dist[V];
int pre[V];

struct Edge{
    int u,v,c,cost,next;
}edge[E];
int head[V],cnt;

void init(){
    cnt=0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int c,int cost)
{
    edge[cnt].u=u;edge[cnt].v=v;edge[cnt].cost=cost;
    edge[cnt].c=c;edge[cnt].next=head[u];head[u]=cnt++;

    edge[cnt].u=v;edge[cnt].v=u;edge[cnt].cost=-cost;
    edge[cnt].c=0;edge[cnt].next=head[v];head[v]=cnt++;
}

bool spfa(int begin,int end){
    int u,v;
    queue<int> q;
    for(int i=0;i<=end+2;i++){
        pre[i]=-1;
        vis[i]=0;
        dist[i]=inf;
    }
    vis[begin]=1;
    dist[begin]=0;
    q.push(begin);
    while(!q.empty()){
        u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i!=-1;i=edge[i].next){
            if(edge[i].c>0){
                v=edge[i].v;
                if(dist[v]>dist[u]+edge[i].cost){
                    dist[v]=dist[u]+edge[i].cost;
                    pre[v]=i;
                    if(!vis[v]){
                        vis[v]=true;
                        q.push(v);
                    }
                }
            }
        }
    }
    return dist[end]!=inf;
}

int MCMF(int begin,int end){
    int ans=0,flow;
    int flow_sum=0;
    while(spfa(begin,end)){
        flow=inf;
        for(int i=pre[end];i!=-1;i=pre[edge[i].u])
            if(edge[i].c<flow)
                flow=edge[i].c;
        for(int i=pre[end];i!=-1;i=pre[edge[i].u]){
            edge[i].c-=flow;
            edge[i^1].c+=flow;
        }
        ans+=dist[end];
        flow_sum += flow;
    }
    //cout << flow_sum << endl;
    return ans;
}

int main()
{
    //freopen("in.txt","r",stdin);
    int n,m,a,b,c;
    while(scanf("%d%d",&n,&m)!=EOF){
        init();
        addedge(0,1,2,0);
        addedge(n,n+1,2,0);
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&a,&b,&c);
            addedge(a,b,1,c);
            addedge(b,a,1,c);
        }
        printf("%d\n",MCMF(0,n+1));
    }
    return 0;
}

poj 2195

建图,不难理解

代码


#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <queue>
#define V 10100
#define E 1000100
#define inf 99999999
const int maxn = 100 + 50 ;
using namespace std;
int vis[V];
int dist[V];
int pre[V];
char maze[maxn][maxn];
int dce[maxn][maxn];
struct nd{
    int x,y;

};
vector<nd>vh;
vector<nd>vm;
struct Edge{
    int u,v,c,cost,next;
}edge[E];
int head[V],cnt;

void init(){
    cnt=0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int c,int cost)
{
    edge[cnt].u=u;edge[cnt].v=v;edge[cnt].cost=cost;
    edge[cnt].c=c;edge[cnt].next=head[u];head[u]=cnt++;

    edge[cnt].u=v;edge[cnt].v=u;edge[cnt].cost=-cost;
    edge[cnt].c=0;edge[cnt].next=head[v];head[v]=cnt++;
}

bool spfa(int begin,int end){
    int u,v;
    queue<int> q;
    for(int i=0;i<=end+2;i++){
        pre[i]=-1;
        vis[i]=0;
        dist[i]=inf;
    }
    vis[begin]=1;
    dist[begin]=0;
    q.push(begin);
    while(!q.empty()){
        u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i!=-1;i=edge[i].next){
            if(edge[i].c>0){
                v=edge[i].v;
                if(dist[v]>dist[u]+edge[i].cost){
                    dist[v]=dist[u]+edge[i].cost;
                    pre[v]=i;
                    if(!vis[v]){
                        vis[v]=true;
                        q.push(v);
                    }
                }
            }
        }
    }
    return dist[end]!=inf;
}

int MCMF(int begin,int end){
    int ans=0,flow;
    int flow_sum=0;
    while(spfa(begin,end)){
        flow=inf;
        for(int i=pre[end];i!=-1;i=pre[edge[i].u])
            if(edge[i].c<flow)
                flow=edge[i].c;
        for(int i=pre[end];i!=-1;i=pre[edge[i].u]){
            edge[i].c-=flow;
            edge[i^1].c+=flow;
        }
        ans+=dist[end];
        flow_sum += flow;
    }
    //cout << flow_sum << endl;
    return ans;
}

int main()
{
    //freopen("in.txt","r",stdin);
    int n,m,a,b,c;
    int M,H;
    while(scanf("%d%d",&n,&m)!=EOF&&!(n==0&&m==0)){
           M=H=0;
           vm.clear();
           vh.clear();
    for(int i=1;i<=n;i++){
            getchar();
            for(int j=1;j<=m;j++){
                scanf("%c",&maze[i][j]);
                if(maze[i][j]=='m'){M++;nd t;t.x=i,t.y=j;vm.push_back(t);}
                if(maze[i][j]=='H'){H++;nd t;t.x=i,t.y=j;vh.push_back(t);}
            }

    }
        init();
       // deal();
        for(int i=1;i<=M;i++)addedge(0,i,1,0);
        for(int i=M+1;i<=M+H;i++)addedge(i,M+H+1,1,0);
        for(int i=0;i<M;i++){
                nd t1=vm[i];
                for(int j=0;j<H;j++){
                    nd t2=vh[j];
                    int dis=abs(t1.x-t2.x)+abs(t1.y-t2.y);
                    addedge(i+1,j+M+1,1,dis);
                }

        }
        printf("%d\n",MCMF(0,M+H+1));
    }
    return 0;
}


poj 2516

题意:有N个客户,M个仓库,和K种货物。已知每个客户需要每种货物的数量,每个仓库存储每种货物的数量,每个仓库运输各种货物去各个客户的单位费用。判断所有的仓库能否满足所有客户的需求,如果可以,求出最少的运输总费用。

构图:K次最小费用最大流。过程中如果有最大流小于总需求则可判不可行。


恩,这是个模板题


#include<cstdio>
#include<cstring>
#include<queue>
#define MAXN 100
#define MAXE 10000
#define INF 0x7fffffff
#define MIN(a,b) a>b?b:a
using namespace std;
int shkp[MAXN][MAXN],supp[MAXN][MAXN],cost[MAXN][MAXN][MAXN];
int head[MAXN],dist[MAXN],vist[MAXN],pre[MAXN],pos[MAXN];
int cnt;
int n,m,k;
int st,ed;
int mincost,maxflow;
struct Edge
{
   int to;
   int cap;
   int cost;
   int next;
}edge[MAXE];

void add(int u,int v,int cap,int cost)
{
   edge[cnt].to=v;
   edge[cnt].cap=cap;
   edge[cnt].cost=cost;
   edge[cnt].next=head[u];
   head[u]=cnt++;

   edge[cnt].to=u;
   edge[cnt].cap=0;
   edge[cnt].cost=-cost;
   edge[cnt].next=head[v];
   head[v]=cnt++;
}

void MCMF(int st,int ed)
{
   int i,u,v;
   int aug;
   mincost=maxflow=0;
   for(;;)
   {
		memset(vist,0,sizeof(vist));
	   memset(pre,-1,sizeof(pre));
       //memset(dist,INF,sizeof(dist));
	   //memset赋值时,容易溢出变负数,一晚上错这里了!!!
	   for(i=0;i<=ed;i++)
		   dist[i]=INF;
       dist[st]=0;
       pre[st]=st;
       vist[st]=1;
	   queue<int> q;
       q.push(st);
       while(!q.empty())
       {
          u=q.front();
	      q.pop();
	      vist[u]=0;
	      for(i=head[u];i!=-1;i=edge[i].next)
	      {
		    v=edge[i].to;
		    if(edge[i].cap>0&&dist[v]>dist[u]+edge[i].cost)
		    {
		       dist[v]=dist[u]+edge[i].cost;
		       pre[v]=u;
		       pos[v]=i;
		       if(!vist[v])
			   {
				   vist[v]=1;
			       q.push(v);
			   }
			}
		  }
	   }
        //if(pre[ed]==-1)
	   if(dist[ed]==INF)  //这两个条件是等价的
			break;
		aug=INF;
		for(u=ed;u!=st;u=pre[u])
			aug=MIN(aug,edge[pos[u]].cap);
		maxflow+=aug;
		mincost+=dist[ed]*aug;
		for(u=ed;u!=st;u=pre[u])
		{
		   edge[pos[u]].cap-=aug;
		   edge[pos[u]^1].cap+=aug;
		}
   }
}

int main()
{
	int i,j,r;
	int need,totalcost,totalflow;
	while(scanf("%d%d%d",&n,&m,&k)!=EOF)
	{
		 if(!n&&!m&&!k)
		   return 0;
		need=0;
		totalcost=0;
		totalflow=0;
	   for(i=1;i<=n;i++)
		   for(j=1;j<=k;j++)
		   {
			   scanf("%d",&shkp[i][j]);
			   need+=shkp[i][j];
		   }
		for(i=1;i<=m;i++)
			for(j=1;j<=k;j++)
				scanf("%d",&supp[i][j]);
		for(r=1;r<=k;r++)
			for(i=1;i<=n;i++)
				for(j=1;j<=m;j++)
					scanf("%d",&cost[r][i][j]);
		for(r=1;r<=k;r++)
		{
		   cnt=0;
		   memset(head,-1,sizeof(head));
		   for(i=1;i<=m;i++)
			   add(0,i,supp[i][r],0);
		   for(i=1;i<=n;i++)
			   add(i+m,m+n+1,shkp[i][r],0);
		   for(i=1;i<=n;i++)
			   for(j=1;j<=m;j++)
				   add(j,i+m,INF,cost[r][i][j]);
			st=0;
			ed=n+m+1;
			MCMF(st,ed);
			totalcost+=mincost;
			totalflow+=maxflow;
		}
		if(totalflow!=need)
			totalcost=-1;
		printf("%d\n",totalcost);
	}
    return 0;
}



http://blog.youkuaiyun.com/z309241990/article/details/38531655

http://blog.youkuaiyun.com/mypsq/article/details/38467727

这个是进阶(网络流)涉及的比较难

线性规划与网络流 一.线性规划问题及其表示 例如: 二.最大网络流问题    (1) 网络   G是一个简单有向图,G=(V,E),V={1,2,…,n}。   在V中指定一个顶点s,称为源和另一个顶点t,称为汇。   有向图G的每一条边(v,w)∈E,对应有一个值cap(v,w)≥0,称为边的容量。   这样的有向图G称作一个网络。 (2) 网络流 阅读详情

相关推荐

[Linux]双网卡 CentOS 系统中指定网络请求走特定网卡的配置方法

本文详细介绍了在双网卡CentOS系统中指定特定域名/IP通过指定网卡传输流量的方法。核心步骤包括:1)确认网卡信息(ip addr)和域名IP解析(nslookup);2)添加临时路由(ip route add);3)持久化配置(创建route-eth1文件);4)验证配置(ip route show和curl测试)。文章还提供了网关查询、路由删除等常见问题的解决方法,并区分了不同CentOS版本重启网络服务的命令差异。通过合理配置路由规则,可实现流量的定向传输需求。

wingaso的博客 1572

网络流 (讲解 + 模板) ----- 详细

文章目录网络流Dinic算法 网络流 感谢博主 : https://www.cnblogs.com/rmy020718/p/9546071.html 感谢博主 : https://www.cnblogs.com/hyserendipity/p/8560525.html 感谢博主 : https://blog.youkuaiyun.com/weixin_43907802/article/details/84705855 感谢博主 : https://www.cnblogs.com/passione-123456/p/12

沐白白的博客 3741

Ubuntu22.04下ROS2与PX4仿真环境搭建全流程解析

本文详细解析了在Ubuntu22.04系统下搭建ROS2与PX4仿真环境的全流程,包括系统准备、ROS2 Humble安装、PX4飞控环境部署、ROS2与PX4通信桥梁搭建等关键步骤。针对常见问题提供了解决方案,并分享了性能优化和开发调试技巧,帮助开发者快速构建无人机仿真开发环境。

weixin_29248653的博客 607

网络流(一) 最大流问题

在一个有向图上选择一个源点,一个汇点,每一条边上都有一个流量上限(以下称为容量),即经过这条边的流量不能超过这个上界,同时,除源点和汇点外,所有点的入流和出流都相等,而源点只有流出的流,汇点只有汇入的流。这样的图叫做网络流。

这里是阿安的博客 5519

告别理论!手把手教你用Patran/Nastran搞定悬臂翼的颤振分析(附完整模型文件)

本文提供了一份详细的Patran/Nastran悬臂翼颤振分析实战指南,涵盖从几何建模到结果解读的全过程。通过手把手教学和完整模型文件,帮助工程师和学生快速掌握气动弹性分析技术,特别适合需要实际操作的初学者。文章重点介绍了模态分析、气动建模和颤振求解等关键步骤,并提供了常见问题排查和优化建议。

weixin_30879169的博客 493

Dev-C++使用技巧2(亲测)(更改字体和颜色、自动保存、快捷键选项、一键排版)

更改字体和颜色 顶部菜单栏->工具->编辑器选项。 更改字体 当前选项卡->显示,字体word有的基本都有,华文楷体、宋体,幼圆之类。西文字体默认字体Consloas就不错,中文的话幼圆、新宋体都挺不错。 幼圆效果: 新宋体效果: 更改颜色 当前选项卡->语法,分别单击图中的部分,然后在左边修改前景颜色就可以了。需要直接显示的修改前景颜色,背景颜色设为白色;需要选中显示的修改背景颜色,前景设为白色。 自动保存 我们有时候忘记保存或者电脑突然关机,可能会丢失代码。

魔神之云的博客 2万+

网络流(Flow Network)

网络流。

KaiserWilheim的博客 3230

windows局域网文件夹共享

windows局域网共享文件夹,亲测,包括可能出现的一些问题解决

yml15180824993的博客 4万+

[网络流]学习笔记:一次理解网络流!

学一个新算法,总要翻多而杂的blog,收获不多。所以我就致力于把学习笔记总结,希望一遍看懂。 简单入门 (但是不全) 一、从概念入手 网络流用于解决流量问题 网络流:所有弧上流量的集合f={f(u,v)},称为该容量网络的一个网络流. 定义:带权的有向图G=(V,E),满足以下条件,则称为网络流图(flow network): 仅有一个入度为0的顶点s,称s为源点 仅有一个出...

A_Comme_Amour的博客 4万+

C#上位机与西门子PLC全链路通信实战教程:数据采集+SQL存储+数据库报表查询+报警历史完整实现

在工业自动化领域,西门子PLC(S7-200Smart/1200/1500)凭借稳定的性能、强大的功能、完善的生态,稳居工业控制器的主流地位;而凭借开发效率高、界面美观、兼容性强、数据库操作便捷的优势,成为工业上位机开发的首选编程语言。二者的组合,是目前制造业、自动化产线、智能仓储、暖通自控等场景的绝对主流方案,也是工业上位机工程师必须吃透的核心技术栈。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1865

ESP-IDF OTA升级过程中遇到的“esp_transport_read returned:-1 and errno:128”问题(4)

ESP-IDF OTA升级过程中遇到的“esp_transport_read returned:-1 and errno:128”问题(4)

phmatthaus的专栏 1532

网络流及其算法

网络流 源点 流量为 inf⁡\infinf 的一个点,网络流起点,一般用 sss 表示。 汇点 接收流量的一个点,网络流终点。 弧 一条有向边。 弧的流量 实际通过这条弧的流量。 弧的容量 指的是一条弧的最大流量。 网络流 所有弧上流量的集合。 增广路径 从源点 sss 到汇点 ttt 的一条可以有流量的路径。 可行弧 也成允许弧,当 (i,j)(i, j)(i,j) 为一个可行弧时,di=dj+1d_i=d_j+1di​=dj​+1,ddd 为当前点 bfsbfsbfs 时的深度 可行流 一张图能够达成

Evan_song1234的博客 2174

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

网络流初步

初略讲解网络流

qq_43052183的博客 2096

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

网络流模板 网络流题型大荟萃

以HDU4560为例,整理了很多网络流的题目—— #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; void fre() { freopen("c://test//inpu

snowy_smile的博客 1263

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

【网络流】

放假以来把网络流看来几篇,今天终于有点感觉,网上很多资料,我认为网络流最难理解的是加反向边,这个东西纠结了很久,网上搜到一个blog才领悟到一句真理:“反向边的作用就是给程序一个可以后悔的机会”,详细请看下面的文章,由于自己对网络流还是vegetables bird,所以只好转一下人家写的好文章。 网络流(Network Flow)      将每条有向

leolin_的专栏 2万+

网络流量分析与网络流量采集:深入了解与实用指南

网络流量分析是指对通过计算机网络传输的数据包进行检测、解析和解读的过程。监控网络性能:通过分析网络流量,可以识别网络瓶颈和性能问题,从而优化网络配置,提高整体网络性能。故障排除:当网络出现问题时,网络流量分析可以帮助快速定位故障点,缩短修复时间。安全防护:通过分析异常流量模式,可以检测网络攻击、数据泄露等安全威胁,并及时采取防护措施。

Johnstons的博客 2630

网络流问题求解及Gurobi+Python代码(最大流/最小成本网络流/多商品网络流)

最大流问题,最小成本网络流,多商品网络流,Gurobi+python代码

weixin_45526117的博客 3312

网络流(1)——网络、流网络和网络流

  在现实世界中,我们的生活受到大量网络的支配。网络流可以表示很多模型,比如管道中的石油、高压线中电流,或者计算机网络中的数据。网络流也可以解决很多问题,比如如何进行道路交通管控,以便有效地缓解早高峰的拥堵;在物流网运输中,在满足供需关系的同时,怎样使渠道成本最低;在轰炸机执行轰炸任务时,怎样才能给敌军补给线造成更严重的打击。这些问题都有现成的网络流算法,别再以为网络流仅仅是网络中的比特流。 网...

我是8位的 1776

网络流总结

上下界网络流 上下界可行流 考虑把每条边必须经过的流量拆出来,那么就变成了某些边必须满流,求一组可行流。我们把必须满流的边拉出来,假想一个源汇 s,t,每条边起点连向 s,t 连向终点,跑 s 到 t 的最大流,若拉出来的边满流就找到了一组可行流。如果本来就有源汇,那么从 t 向 s 连流量正无穷的边,就转成无源汇网络流了。 上下界最大流 先求出一个可行流,把连向超级源汇的边删掉,再从 s 到 t...

Hellsegamosken 956

一篇网络流的好blog

网络流最近在学习二分图匹配,网络流和博弈论(%eazy,miaomiao,lsr_dalao,zyh,zlt),感谢诸位牛犇给蒟蒻的讲课,让我受益匪浅,PPT就不放上来了,有版权问题,下面我给大家谈谈我近期学习网络流的心得。(因为前几天感冒落了些进度,感谢ergeda和脑屁股的细心辅导)。微笑吐舌头一:what is 网络流???根据lsr_dalao的ppt上所言: 定义: 图论中的一种理

BroDrinkWater的博客 5950

网络流C++

网络流C++

缪语博的博客 1296

图论 —— 网络流

【概述】 网络流是一个适用范围极广的模型,相关的算法也很多,大体分为最大流、最小割、费用流三类。 对于网络流类型的题来说,一般根据题意,分析后建出图后,套用相关模版,即可解决问题。 关于网络流的基本概念与建模技巧:点击这里 【算法】 1.最大流算法 求最大流算法分为两类,一种是增广路算法,一种是预留推进算法。 增广路算法,常用的有时间复杂度 O(n*m*m) 的 FF 算法、EK 算...

Alex_McAvoy的博客 3533

网络流详解

文章目录网络流定义最大流最大流建模残量网络增广引理证明求流量增广路结论割割的流量割的容量最小割引理2推论最小割最大流定理证明网络流算法Ford-FulkersonEdmonds-Karp引理Dinic​LCT优化当前弧优化单位容量网络单位网络例题最大权闭合子图海拔后记 网络流 定义 网络流图定义 每条边有两个权值,容量和流量 流量不超过每条边的容量 流量守恒,每个点流进来和流出去的容量一样 源点...

lcy19260817的博客 1047
上一篇: hdu 1496
下一篇: 二分图 匈牙利算法应用
is_it_a_error
博客等级 码龄11年 1粉丝 31原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值