zoukankan      html  css  js  c++  java
  • hdu 3416(最短路+最大流)

    题目链接: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     
  • 相关阅读:
    [ jquery 选择器 :hidden ] 此方法选取匹配所有不可见元素,或者type为hidden的元素
    剑指 Offer 03. 数组中重复的数字 哈希
    LeetCode 1736. 替换隐藏数字得到的最晚时间 贪心
    Leetcode 1552. 两球之间的磁力 二分
    Leetcode 88. 合并两个有序数组 双指针
    LeetCode 1744. 你能在你最喜欢的那天吃到你最喜欢的糖果吗?
    LeetCode 1743. 相邻元素对还原数组 哈希
    LeetCode 1745. 回文串分割 IV dp
    剑指 Offer 47. 礼物的最大价值 dp
    剑指 Offer 33. 二叉搜索树的后序遍历序列 树的遍历
  • 原文地址:https://www.cnblogs.com/wally/p/3060452.html
Copyright © 2011-2022 走看看