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; }