hdu 3416(最短路+最大流)

来源:互联网 发布:外交官 新秀丽 知乎 编辑:程序博客网 时间:2024/05/21 10:01

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3416

思路:就是先求一次最短路,最短路我们可以用spfa求出,然后取出最短路上的边建图,容量为1,最后一次SAP即可求出所有路径条数。

View Code
  1 #include<iostream>  2 #include<cstring>  3 #include<cstdio>  4 #include<queue>  5 #include<vector>  6 using namespace std;  7 #define MAXM 333333  8 #define MAXN 2222  9 #define inf 0x3f3f3f3f 10 struct Node{ 11     int v,cap; 12 }; 13 vector<Node>vet[MAXN]; 14 struct Edge{ 15     int v,cap,next; 16 }edge[MAXM]; 17  18 int head[MAXN]; 19 int cur[MAXN]; 20 int pre[MAXN]; 21 int level[MAXN]; 22 int gap[MAXN]; 23 int NV,NE,n,m,vs,vt; 24  25 int dist[MAXN]; 26 bool visited[MAXN]; 27  28 void Insert(int u,int v,int cap,int cc=0){ 29     edge[NE].v=v;edge[NE].cap=cap; 30     edge[NE].next=head[u];head[u]=NE++; 31  32     edge[NE].v=u;edge[NE].cap=cc; 33     edge[NE].next=head[v];head[v]=NE++; 34 } 35  36 //spfa求出最短路径 37 void spfa(){ 38     memset(visited,false,sizeof(visited)); 39     for(int i=1;i<=n;i++)dist[i]=inf; 40     dist[vs]=0;; 41     queue<int>Q; 42     Q.push(vs); 43     while(!Q.empty()){ 44         int u=Q.front(); 45         Q.pop(); 46         visited[u]=false; 47         for(int i=0;i<vet[u].size();i++){ 48             int v=vet[u][i].v; 49             int w=vet[u][i].cap; 50             if(dist[u]+w<dist[v]){ 51                 dist[v]=dist[u]+w; 52                 if(!visited[v]){ 53                     visited[v]=true; 54                     Q.push(v); 55                 } 56             } 57         } 58     } 59 } 60  61  62  //参数,源点,汇点 63  int SAP(int vs,int vt){ 64      memset(level,0,sizeof(level)); 65      memset(pre,-1,sizeof(pre)); 66      memset(gap,0,sizeof(gap)); 67      //cur[i]保存的是当前弧 68      for(int i=0;i<=NV;i++)cur[i]=head[i]; 69      int u=pre[vs]=vs;//源点的pre还是其本身 70      int maxflow=0,aug=-1; 71      gap[0]=NV; 72      while(level[vs]<NV){ 73  loop : 74          for(int &i=cur[u];i!=-1;i=edge[i].next){ 75              int v=edge[i].v;//v是u的后继 76              //寻找可行弧 77              if(edge[i].cap&&level[u]==level[v]+1){ 78                  //aug表示增广路的可改进量 79                 aug==-1?(aug=edge[i].cap):(aug=min(aug,edge[i].cap)); 80                 // if(aug>edge[i].cap)aug=edge[i].cap; 81                  pre[v]=u; 82                  u=v; 83                  //如果找到一条增广路 84                  if(v==vt){ 85                      maxflow+=aug;//更新最大流; 86                      //路径回溯更新残留网络 87                      for(u=pre[v];v!=vs;v=u,u=pre[u]){ 88                          //前向弧容量减少,反向弧容量增加 89                          edge[cur[u]].cap-=aug; 90                          edge[cur[u]^1].cap+=aug; 91                      } 92                      aug=-1; 93                     // aug=inf; 94                  } 95                  goto loop; 96              } 97          } 98          int minlevel=NV; 99          //寻找与当前点相连接的点中最小的距离标号(重标号)100          for(int i=head[u];i!=-1;i=edge[i].next){101              int v=edge[i].v;102              if(edge[i].cap&&minlevel>level[v]){103                  cur[u]=i;//保存弧104                  minlevel=level[v];105              }106          }107          if((--gap[level[u]])==0)break;//更新gap数组后如果出现断层,则直接退出。108          level[u]=minlevel+1;//重标号109          gap[level[u]]++;//距离标号为level[u]的点的个数+1;110          u=pre[u];//转当前点的前驱节点继续寻找可行弧111      }112      return maxflow;113  } 114 115 116 int main(){117     int _case,u,v,d;118     scanf("%d",&_case);119     while(_case--){120         scanf("%d%d",&n,&m);121         for(int i=1;i<=n;i++)vet[i].clear();122         for(int i=1;i<=m;i++){123             scanf("%d%d%d",&u,&v,&d);124             if(u==v)continue;125             Node p;126             p.v=v,p.cap=d;127             vet[u].push_back(p);//vector建邻接表128         }129         scanf("%d%d",&vs,&vt);130         spfa();131         NE=0,NV=n;132         memset(head,-1,sizeof(head));133         for(int i=1;i<=n;i++){134             for(int j=0;j<vet[i].size();j++){135                 //如果是最短路径上的边,就建图,且边容量为1;136                 if(dist[vet[i][j].v]==dist[i]+vet[i][j].cap){137                     Insert(i,vet[i][j].v,1);138                 }139             }140         }141         printf("%d\n",SAP(vs,vt));142     }143     return 0;144 }145 146     

 

0 0
原创粉丝点击