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;

}

你可能感兴趣的:(NetWork)