码迷,mamicode.com
首页 > 其他好文 > 详细

POJ 3281 Dining 【最大流】

时间:2018-08-23 02:06:55      阅读:152      评论:0      收藏:0      [点我收藏+]

标签:iostream   记录   inf   style   turn   for   min   div   起点   

完全体网络流。。

拿vector实现了一次,这样的话网络流的所有实现方法我都写过一遍了

#include<iostream>
#include<deque>
#include<vector>
#include<cstring>
#define INF 2e9
using namespace std;

int N,F,D,T;

struct edge{
    int v,cap,reverse;
};
vector<int> edges[1005];//邻接表 
vector<edge> bian;//所有的边都存在里面 

void addedge(int u,int v,int cap){//u到v一条边,再加一条反向边 
    edge e;
    e.cap=cap;
    e.v=v;
    e.reverse=bian.size()+1;//这条边的反边将建在这条边之后(这条边建完后在bian.size()的位置) 
    bian.push_back(e);
    edges[u].push_back(bian.size()-1);
    
    e.cap=0;
    e.v=u;
    e.reverse=bian.size()-1;
    bian.push_back(e);
    edges[v].push_back(bian.size()-1);
}

int layer[1005],vis[1005];
bool count_layer(){
    memset(layer,0,sizeof(layer));
    deque<int> q;
    layer[0]=1; q.push_back(0);
    while( !q.empty() ){
        int u = q.front(); q.pop_front();
        if( u==T ) return true;
        for(int i=0;i<edges[u].size();i++){//所有以u为起点的边的边的索引 
            edge &e = bian[ edges[u][i] ];
            int v=e.v;
            if( !layer[v] && e.cap>0 ){
                layer[v] = layer[u] + 1;
                q.push_back( v );
            }
        }
    }
    return false;
}

int dinic(){
    int max_flow=0;
    while( count_layer() ){
        memset(vis,0,sizeof(vis));
        deque<int> q,path;//记录一路走过来的【点】和【边的索引】 
        q.push_back(0); vis[0]=1;
        while(!q.empty()){
            int u = q.back();
            if( u==T ){
                int min_u,min_v,min_flow=INF;
                int p=0;//从0点出发 
                for(int i=0;i<path.size();i++){
                    edge &e = bian[ path[i] ];
                    if( e.cap<min_flow ){
                        min_u=p;
                        min_flow=e.cap;
                    }
                    p=e.v;
                }
                
                p=0;
                max_flow+=min_flow;
                for(int i=0;i<path.size();i++){
                    edge &e = bian[ path[i] ];
                    e.cap-=min_flow;
                    bian[e.reverse].cap+=min_flow;
                }
                //回溯
                while( !q.empty() && q.back()!=min_u ){
                    vis[ q.back() ]=0;
                    q.pop_back();
                    path.pop_back();
                } 
            }
            else{//T边 
                int i;
                for(i=0;i<edges[u].size();i++){
                    edge &e = bian[ edges[u][i] ];
                    if( layer[e.v]==layer[u]+1 && !vis[e.v] && e.cap>0 ){
                        vis[e.v]=1;
                        q.push_back( e.v );
                        path.push_back( edges[u][i] );
                        break;
                    }
                }
                if(i==edges[u].size()) {
                    q.pop_back();
                    path.pop_back();
                }
            }        
            
        }
    }
    return max_flow;
}

int main(){
    //food编号1 - F
    //把一头牛拆成两头 
    //cows1编号F+1 - F+N 
    //cows2编号F+N+1 - F+N+N 
    //drink编号F+2N+1 - F+2N+D
    cin>>N>>F>>D;
     T=N+N+F+D+1;
    for(int i=1;i<=N;i++){
        int fi,di,food,drink; cin>>fi>>di;
        for(int j=1;j<=fi;j++) cin>>food,addedge(food,F+i,1);//food到奶牛1建一条边
        for(int j=1;j<=di;j++) cin>>drink,addedge(F+N+i,F+2*N+drink,1);//从奶牛2到drink建一条边
    }

    for(int i=F+1;i<=F+N;i++) addedge(i,i+N,1);//奶牛1到奶牛2建一条边 
    for(int i=1;i<=F;i++) addedge(0,i,1);//从源点0到所有food建边
    for(int i=F+2*N+1;i<=F+2*N+D;i++) addedge(i,T,1); //从所有drink到汇点F+D+2*N+1建边
     
    cout<<dinic();
    return 0;    
}

 

POJ 3281 Dining 【最大流】

标签:iostream   记录   inf   style   turn   for   min   div   起点   

原文地址:https://www.cnblogs.com/ZhenghangHu/p/9521288.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!