题目链接: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