網絡流


上連接:

初期,比較簡單

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

這個是進階(網絡流)涉及的比較難

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章