uva 10330 Power Transmission

最大流水题

题意:给n个点从1到n标号,每个点有一个限制值a[i],表示从这个点流出的流量的最大值,就算有超过a[i]的流量流进i点,最后也只有a[i]流量从i点流出。然后每条有向边也有容量cap[u][v]

然后给你一个源点0,它会和一些顶点相连,这些边的容量是无穷大的,然后给你一个汇点n+1,也会和一些顶点相连,这些边的容量也是无穷大的,

然后求源点到汇点的最大流

想了一下,有思路,无非是处理一下边的容量,起初想是对于有向边  u---->v  cap[u][v]=min( cap[u][v] , a[u]);  处理完就直接最大流模板上去,过了sample,提交WA,后来才想到是

cap[u][v]=min( cap[u][v] , a[u] , a[v]);  提交WA………………才想起来,那些无穷大的边的容量没有做处理,和源点关联的边的容量由无穷大改为与之相连的那个点的限制值a[v] ,与汇点关联的那些边的容量改为那个点的限制值a[u],然后最大流模板直接上去,AC了,水题遂过

 

然后查了一下网上的解题报告,说是要拆成两点,然后连一条边,容量就是限制值,拆点的代码这里没给出,下次再写了

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define N 110
#define INF 0x3f3f3f3f
int cap[N][N];
int n,m,numb,numd;  //源点和汇点
int a[N]; //a是每个顶点的限制量

void input()
{
    memset(cap,0,sizeof(cap));
    for(int i=1; i<=n; i++)
        scanf("%d",&a[i]);
    scanf("%d",&m);
    for(int i=1; i<=m; i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        cap[u][v]+=w;
        if(cap[u][v]>a[u])
            cap[u][v]=a[u];
        if(cap[u][v]>a[v])
            cap[u][v]=a[v];
    }
    scanf("%d%d",&numb,&numd);
    for(int i=1; i<=numb; i++)
    {
        int v;
        scanf("%d",&v);
        cap[0][v]=a[v];
    }
    for(int i=1; i<=numd; i++)
    {
        int u;
        scanf("%d",&u);
        cap[u][n+1]=a[u];
    }

    return ;
}
void print_graph()
{
    for(int i=0; i<=n+1; i++)
    {
        for(int j=0; j<=n+1; j++)
            printf("%d ",cap[i][j]);
        printf("\n");
    }
    return ;
}
void EK()
{
    int F=0;  //记录最终最大流
    int min[N];  //记录最小残余流量
    int p[N];  //记录路径
    int flow[N][N];  //流量
    memset(flow,0,sizeof(flow));
    while(1)
    {
        memset(min,0,sizeof(min)); min[0]=INF;  //递推数组,每次增广路找最小值
        memset(p,-1,sizeof(p));
        queue <int> q;
        q.push(0);
        while(!q.empty())  //BFS
        {
            int u=q.front(); q.pop();
            for(int v=0; v<=n+1; v++)
                if( !min[v] && cap[u][v]>flow[u][v])
                {
                    p[v]=u; q.push(v);
                    min[v]=min[u]<(cap[u][v]-flow[u][v]) ? min[u] : (cap[u][v]-flow[u][v]);
                }
        }

        if(!min[n+1])  break;
        
        for(int u=n+1; u!=0; u=p[u])  //增广
        {
            flow[p[u]][u]+=min[n+1];
            flow[u][p[u]]-=min[n+1];
        }
        F+=min[n+1];
    }
    printf("%d\n",F);
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        input();
        //print_graph();
        EK();  //EK算法求最大流
    }
    return 0;
}
posted @ 2012-11-30 22:50  Titanium  阅读(536)  评论(1编辑  收藏  举报