Hoj 1228/Poj 1459 Power Network

题目链接:http://acm.hit.edu.cn/hoj/problem/view?id=1228

http://poj.org/problem?id=1459

本题是练习网络流的模板题。

按照BFS求最大流即可。另开两个节点做超级起始点和超级终结点。

Poj一遍过,为啥Hoj用Scanf读数据会超时,改成Cin就A了,无语。

先写增广路算法。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

#define Maxn 105
#define INF 1<<30

vector<int> node[Maxn];
//容量
int cap[Maxn][Maxn];
//流量
int flow[Maxn][Maxn];
//起始点到当前节点的最小残量
int a[Maxn];
//记录父亲节点
int p[Maxn];

void init()
{
    for(int i=0; i<Maxn; i++)
    {
        node[i].clear();
    }
}
int edmondsKarp(int s,int t)
{
    //最大流值
    int f = 0;
    queue<int> q;
    memset(flow,0,sizeof(flow));
    for(;;)
    {
        memset(a,0,sizeof(a));
        a[s] = INF;
        q.push(s);
        while(!q.empty())
        {
            int u = q.front();
            q.pop();
            int size = node[u].size();
            for(int i=0; i<size; i++)
            {
                int v = node[u][i];
                if(cap[u][v]>flow[u][v] && !a[v])
                {
                    a[v] = a[u] < cap[u][v] - flow[u][v] ? a[u] : cap[u][v] - flow[u][v];
                    p[v] = u;
                    q.push(v);
                }
            }
        }
        if(a[t] == 0) return f;
        for(int u = t; u!=s; u=p[u])
        {
            flow[p[u]][u] += a[t];
            flow[u][p[u]] -= a[t];
        }
        f += a[t];
    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
#endif
    int n,np,nc,m;
    int u,v,z;
    int s,t;
    while(cin>>n>>np>>nc>>m)
    //为什么HOJ改成scanf会超时?
    //while(scanf(" %d %d %d %d",&n,&np,&nc,&m)!=EOF)
    {
        init();
        for(int i=0; i<m; i++)
        {
            scanf(" (%d,%d)%d",&u,&v,&z);
            if(u!=v)
            {
                cap[u][v] = z;
                node[u].push_back(v);
            }
        }
        //建立超级起始点和超级终结点
        s = n,t = n+1;
        for(int i=0; i<np; i++)
        {
            scanf(" (%d)%d",&u,&z);
            cap[s][u] = z;
            node[s].push_back(u);
        }
        for(int i=0; i<nc; i++)
        {
            scanf(" (%d)%d",&u,&z);
            cap[u][t] = z;
            node[u].push_back(t);
        }
        printf("%d\n",edmondsKarp(s,t));
    }
    return 0;
}

补充一下Dicnic算法,这种情况一定要插入两条边,第二条边的cap为0。

果然快不少:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stack>
#include <queue>
#include <algorithm>
#include <iostream>

using namespace std;

#define Maxn 105
#define Maxm 400005
#define INF 1<<30
struct Edge
{
    int a,b;
    int cap,flow;
};

struct Dicnic
{
    Edge edge[Maxm];
    int first[Maxn];
    int next[Maxm];
    int total;
    int s,t;
    int vis[Maxn],d[Maxn],cur[Maxn];
    void init()
    {
        total = 0;
        memset(first,-1,sizeof(first));
    }
    void addEdge(int a,int b,int w)
    {
        edge[total].a = a,edge[total].b = b,edge[total].cap = w;
        edge[total].flow = 0;
        next[total] = first[a];
        first[a] = total++;
    }
    bool bfs()
    {
        memset(vis,0,sizeof(vis));
        queue <int> q;
        q.push(s);
        vis[s] = 1;
        d[s] = 0;
        while(!q.empty())
        {
            int x = q.front();
            q.pop();
            for(int i=first[x];i!=-1;i=next[i])
            {
                int y = edge[i].b;
                if(!vis[y] && edge[i].cap > edge[i].flow)
                {
                    vis[y] = 1;
                    d[y] = d[x] + 1;
                    q.push(y);
                }
            }
        }
        return vis[t];
    }
    int dfs(int x,int a)
    {
        if(x == t || a == 0) return a;
        int flow = 0;
        int f;
        for(int &i = cur[x];i!=-1;i=next[i])
        {
            Edge &e = edge[i];
            if(d[x] + 1 == d[e.b])
            {
                f = dfs(e.b,min(a,e.cap - e.flow));
                if(f > 0)
                {
                    e.flow += f;
                    edge[i^1].flow -= f;
                    flow += f;
                    a -= f;
                    if(a == 0) break;
                }
            }
        }
        return flow;
    }
    int maxFlow(int s,int t)
    {
        this->s = s,this->t = t;
        int flow = 0;
        while(bfs())
        {
            memcpy(cur,first,sizeof(first));
            flow += dfs(s,INF);
        }
        return flow;
    }
}dicnic;

int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
    #endif
    int n,np,nc,m;  
    int u,v,z;  
    int s,t;  
    while(cin>>n>>np>>nc>>m)
    //while(scanf(" %d %d %d %d",&n,&np,&nc,&m)!=EOF)  
    {
        dicnic.init();  
        for(int i=0; i<m; i++)  
        {  
            scanf(" (%d,%d)%d",&u,&v,&z);  
            if(u!=v)  
            {  
                dicnic.addEdge(u,v,z);
                dicnic.addEdge(v,u,0); 
            }
        }  
        //建立超级起始点和超级终结点  
        s = n,t = n+1;  
        for(int i=0; i<np; i++)  
        {  
            scanf(" (%d)%d",&u,&z);
            dicnic.addEdge(s,u,z);
            dicnic.addEdge(u,s,0);  
            //cap[s][u] = z;  
            //node[s].push_back(u);  
        }  
        for(int i=0; i<nc; i++)  
        {  
            scanf(" (%d)%d",&u,&z);  
            dicnic.addEdge(u,t,z);
            dicnic.addEdge(t,u,0);
            //cap[u][t] = z;  
            //node[u].push_back(t);  
        }
        //printf("%d\n",edmondsKarp(s,t)); 
        printf("%d\n",dicnic.maxFlow(s,t));
    }  
    return 0;
}

再补充一下ISAP解法:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stack>
#include <queue>
#include <algorithm>
#include <iostream>

using namespace std;

#define Maxn 105
#define Maxm 400005
#define INF 1<<30
struct Edge
{
    int a,b;
    int cap,flow;
};

struct ISAP
{
    Edge edge[Maxm];
    int first[Maxn];
    int next[Maxm];
    int total;
    int s,t;
    int n;
    int vis[Maxn],d[Maxn],cur[Maxn];
    int num[Maxn],p[Maxn];
    void init()
    {
        total = 0;
        memset(first,-1,sizeof(first));
    }
    void initn(int n)
    {
        this->n = n;
    }
    //记着增加反向边
    void addEdge(int a,int b,int w)
    {
        edge[total].a = a,edge[total].b = b,edge[total].cap = w;
        edge[total].flow = 0;
        next[total] = first[a];
        first[a] = total++;
    }
    bool bfs()
    {
        memset(vis,0,sizeof(vis));
        queue <int> q;
        q.push(t);
        vis[t] = 1;
        d[t] = 0;
        while(!q.empty())
        {
            int x = q.front();
            q.pop();
            for(int i=first[x];i!=-1;i=next[i])
            {
                Edge &e = edge[i^1];
                if(!vis[e.a] && e.cap>e.flow)
                {
                    vis[e.a] = 1;
                    d[e.a] = d[x] + 1;
                    q.push(e.a);
                }
            }
        }
        return vis[s];
    }
    int Augment()
    {
        int x = t,a = INF;
        while(x!=s)
        {
            Edge &e = edge[p[x]];
            a = min(a,e.cap - e.flow);
            x = edge[p[x]].a;
        }
        x = t;
        while(x!=s)
        {
            edge[p[x]].flow += a;
            edge[p[x]^1].flow -= a;
            x = edge[p[x]].a;
        }
        return a;
    }
    int maxFlow(int s,int t)
    {
        this->s = s,this->t = t;
        int flow = 0;
        bfs();
        memset(num,0,sizeof(num));
        for(int i=0;i<n;i++)
        {
            num[d[i]]++;
        }
        int x = s;
        memcpy(cur,first,sizeof(first));
        while(d[s] < n)
        {
            if(x == t)
            {
                flow += Augment();
                x = s;
            }
            int ok = 0;
            for(int i=cur[x];i!=-1;i=next[i])
            {
                Edge &e = edge[i];
                if(e.cap > e.flow && d[x] == d[e.b] + 1)
                {
                    ok = 1;
                    p[e.b] = i;
                    cur[x] = i;
                    x = e.b;
                    break;
                }
            }
            if(!ok)
            {
                int m = n-1;
                for(int i=first[x];i!=-1;i=next[i])
                {
                    Edge &e = edge[i];
                    if(e.cap > e.flow) m = min(m,d[e.b]);
                }
                if(--num[d[x]] == 0) break;
                num[d[x] = m+1]++;
                cur[x] = first[x];
                if(x!=s) x = edge[p[x]].a;
            }
        }
        return flow;
    }
}isap;

int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
    #endif
    int n,np,nc,m;  
    int u,v,z;  
    int s,t;  
    while(cin>>n>>np>>nc>>m)
    //while(scanf(" %d %d %d %d",&n,&np,&nc,&m)!=EOF)  
    {
        isap.init();  
        for(int i=0; i<m; i++)  
        {  
            scanf(" (%d,%d)%d",&u,&v,&z);  
            if(u!=v)  
            {  
                isap.addEdge(u,v,z);
                isap.addEdge(v,u,0); 
            }
        }  
        //建立超级起始点和超级终结点  
        s = n,t = n+1;  
        for(int i=0; i<np; i++)  
        {  
            scanf(" (%d)%d",&u,&z);
            isap.addEdge(s,u,z);
            isap.addEdge(u,s,0);  
            //cap[s][u] = z;  
            //node[s].push_back(u);  
        }  
        for(int i=0; i<nc; i++)  
        {  
            scanf(" (%d)%d",&u,&z);  
            isap.addEdge(u,t,z);
            isap.addEdge(t,u,0);
            //cap[u][t] = z;  
            //node[u].push_back(t);  
        }
        isap.initn(n+2);
        //printf("%d\n",edmondsKarp(s,t)); 
        printf("%d\n",isap.maxFlow(s,t));
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值