POJ1459多源点网络流入门(ISAP)

题意: 
简单的说下题意(按输入输出来讲,前面的描述一堆的rubbish,还用来误导人),给你n个点,其中有np个是能提供电力的点,nc个是能消费电力的点,剩下的点(n-np-nc)是中转战即不提供电力也不消费电力,点与点之间是有线路存在的,有m条线路,每条线路有最多运载限定。 
前4个数据就是有n个点,np个供电点,nc个消费点,m条线路,接来题目先给出的是m条线路的数据,(起点,终点)最多运载量,然后是np个供电点的数据(供电点)最多供电量,接着就是nc个消费点的数据(消费点)最多消费电量。 
题目要我们求出给定的图最大能消费的总电量(就是求最大流)
分析增加一个超级源点,和超级汇点。。把所给的发电站都和超级源点相连,把所给的消耗战都和超级汇点相连

然后需要注意的地方就是输入的地方有点坑,大家注意一下输入的地方就可以了

下面的是我用ISAP做的,正好刚入门网络流,也正好学到ISAP,小试一下QAQ

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdlib>
using namespace std;
const int max_nodes=4e4;
const int INF=0x3f3f3f3f;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define me(a,b) memset(a,b,sizeof a)
typedef long long ll;
struct node
{
    int from,to,capacity,flow;
};
vector<int>G[max_nodes];
vector<node>edges;
vector<int>::iterator it;
int num_nodes;
int source;         // 源点
int sink;           // 汇点
int p[max_nodes];   // 可增广路上的上一条弧的编号
int num[max_nodes]; // 和 t 的最短距离等于 i 的节点数量
int cur[max_nodes]; // 当前弧下标
int d[max_nodes];   // 残量网络中节点 i 到汇点 t 的最短距离
bool vis[max_nodes];
typedef vector<int>::iterator  iterator_t ;
void add(int u,int v,int w){
   edges.push_back((node){u,v,w,0});
   edges.push_back((node){v,u,0,0});
   int k=edges.size();
   G[u].push_back(k-2);
   G[v].push_back(k-1);
}
void bfs(){
    memset(vis,0,sizeof vis);
    memset(d,0,sizeof d);
    queue<int>q;
    q.push(sink);
    vis[sink]=1;
    d[sink]=0;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=0;i<G[u].size();i++){
            node e=edges[G[u][i]^1];
            if(!vis[e.from]&&e.capacity>e.flow){
                vis[e.from]=1;
                d[e.from]=d[u]+1;
                q.push(e.from);
            }
        }
    }
}
int augment(){
    int df=INF,u=sink;
    while(u!=source){
        node e=edges[p[u]];
        df=min(df,e.capacity-e.flow);
        u=edges[p[u]].from;
    }
    u=sink;
    while(u!=source){
        edges[p[u]].flow+=df;
        edges[p[u]^1].flow-=df;
        u=edges[p[u]].from;
    }
    return df;
}
int max_flow(){
    int ans=0;
    bfs();
    memset(num,0,sizeof num);
    for(int i=0;i<num_nodes;i++) num[d[i]]++;
    int u=source;
    memset(p,0,sizeof p);
    memset(cur,0,sizeof cur);
    while(d[source]<num_nodes){
        if(u==sink){
            ans+=augment();
            u=source;
        }
        bool flag=0;
        for(int i=cur[u];i<G[u].size();i++){
            node e=edges[G[u][i]];
            if(e.capacity>e.flow&&d[u]==d[e.to]+1){
                flag=1;
                p[e.to]=G[u][i];
                cur[u]=i;
                u=e.to;
                break;
            }
        }
        if(!flag){
            int m=num_nodes-1;
            for(int i=0;i<G[u].size();i++){
                node e=edges[G[u][i]];
                if(e.capacity>e.flow)
                    m=min(m,d[e.to]);
            }
            if(--num[d[u]]==0) break;
            num[d[u]=m+1]++;
            cur[u]=0;
            if(u!=source)
                u=edges[p[u]].from;
        }
    }
    return ans;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif // ONLINE_JUDGE
    int n,np,nc,m;
    int u,v,w;
    while(scanf("%d%d%d%d",&n,&np,&nc,&m)!=EOF){
        while(m--){
            while(getchar()!='(');
            scanf("%d,%d)%d",&u,&v,&w);
            u++;v++;
            add(u,v,w);
        }
        while(np--){
            while(getchar()!='(');
            scanf("%d)%d",&u,&w);
            u++;
            add(0,u,w);
        }
        while(nc--){
            while(getchar()!='(');
            scanf("%d)%d",&u,&w);
            u++;
            add(u,n+1,w);
        }
        sink=n+1;
        num_nodes=n+2;
        source=0;
        printf("%d\n",max_flow());
        for(int i=0;i<=num_nodes;i++)
            G[i].clear();
        edges.clear();
    }
    return 0;
}

emmmmm,这个当做模板也是可以的

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值