网络流


上连接:

初期,比较简单

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.csdn.net/z309241990/article/details/38531655

http://blog.csdn.net/mypsq/article/details/38467727

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值