POJ 1459 Power Network【SAP】


http://poj.org/problem?id=1459
POJ 1459 Power Network
大意:已知供电站的最大供电量,消费者的最大消费量,电线传输电量的上限,
求整个供电网的最大供电量
算法核心:SAP

#include<stdio.h>
#include<string.h>
const int N = 100+5;
const int MAXN =N;
const int INF = 20000+200+2;
int S,T;//S为源点,T为汇点
int graph[N][N];
int getNum()
{
 int num = 0;
 char c;
 while(c=getchar())
 {
  if(c<='9'&&c>='0')break;
 }

 while(c<='9'&&c>='0')
 {
  num=num*10+c-'0';
  c=getchar();
 }
 return num;
}

inline void addEdge(int s,int t,int flow)
{
    graph[s][t]+=flow;
}
void init()
{
 memset(graph,0,sizeof(graph));
}

int SAP(int map[][MAXN],int v_count,int s,int t)      //邻接矩阵,节点总数,始点,汇点   
{   
 int i;   
 int cur_flow,max_flow,cur,min_label,temp;         //当前流,最大流,当前节点,最小标号,临时变量   
 char flag;                                        //标志当前是否有可行流   
 int cur_arc[MAXN],label[MAXN],neck[MAXN];         //当前弧,标号,瓶颈边的入点(姑且这么叫吧)   
 int label_count[MAXN],back_up[MAXN],pre[MAXN];    //标号为i节点的数量,cur_flow的纪录,当前流路径中前驱   

 //初始化   
 memset(label,0,MAXN*sizeof(int));   
 memset(label_count,0,MAXN*sizeof(int));   

 memset(cur_arc,0,MAXN*sizeof(int));   
 label_count[0]=v_count;                           //全部初始化为距离为0   

 neck[s]=s;   
 max_flow=0;   
 cur=s;   
 cur_flow=INF;   

 //循环代替递归   
 while(label[s]<v_count)   
 {   
  back_up[cur]=cur_flow;   
  flag=0;   

  //选择允许路径(此处还可用邻接表优化)   
  for(i=cur_arc[cur];i<v_count;i++)    //当前弧优化   
  {   
   if(map[cur][i]!=0&&label[cur]==label[i]+1)    //找到允许路径   
   {   
    flag=1;   
    cur_arc[cur]=i;    //更新当前弧   
    if(map[cur][i]<cur_flow)    //更新当前流   
    {   
     cur_flow=map[cur][i];   
     neck[i]=cur;     //瓶颈为当前节点   
    }   
    else 
    {   
     neck[i]=neck[cur];     //瓶颈相对前驱节点不变   
    }   
    pre[i]=cur;    //记录前驱   
    cur=i;   
    if(i==t)    //找到可行流   
    {   
     max_flow+=cur_flow;    //更新最大流   

     //修改残量网络   
     while(cur!=s)   
     {   
      if(map[pre[cur]][cur]!=INF)map[pre[cur]][cur]-=cur_flow;   
      back_up[cur] -= cur_flow;   
      if(map[cur][pre[cur]]!=INF)map[cur][pre[cur]]+=cur_flow;   
      cur=pre[cur];   
     }   

     //优化,瓶颈之后的节点出栈   
     cur=neck[t];   
     cur_flow=back_up[cur];    
    }   
    break;   
   }   
  }   
  if(flag)continue;   

  min_label=v_count-1;    //初始化min_label为节点总数-1   

  //找到相邻的标号最小的节点      
  for(i=0;i<v_count;i++)   
  {   
   if(map[cur][i]!=0&&label[i]<min_label)   
   {   
    min_label=label[i];   
    temp=i;   
   }   
  }   
  cur_arc[cur]=temp;    //记录当前弧,下次从提供最小标号的节点开始搜索   
  label_count[label[cur]]--;    //修改标号纪录   
  if(label_count[label[cur]]==0)break;    //GAP优化   
  label[cur]=min_label+1;    //修改当前节点标号   
  label_count[label[cur]]++;     //修改标号记录   
  if(cur!=s)   
  {   
   //从栈中弹出一个节点   
   cur=pre[cur];   
   cur_flow=back_up[cur];   
  }   
 }   
 return(max_flow);   
}

int main()
{
 int n,np,nc,m;
 while(scanf("%d%d%d%d",&n,&np,&nc,&m)!=EOF)
 {
  S = n;
  T = n+1;
      init();
  int u,v,z;
  while(m--)
  {
       u=getNum();
    v=getNum();
    z=getNum();
    addEdge(u,v,z);
    addEdge(v,u,0);//添加反向边
    //printf("(%d %d)%d\n",u,v,z);
  }

    while(np--)
    {
      u = getNum();
      z = getNum();
   addEdge(S,u,z);
   addEdge(u,S,0);//反向弧
   //printf("(%d)%d\n",u,z);
    }

    while(nc--)
    {
          u = getNum();
    z = getNum();
    addEdge(u,T,z);
    addEdge(T,u,0);
    //printf("(%d)%d\n",u,z);
    }
    printf("%d\n",SAP(graph,T+1,S,T));
 }
 return 0;
}

转载于:https://www.cnblogs.com/AndreMouche/archive/2011/02/23/1962319.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值