hdu 3416 最短路+最大流

 
 
题意:求源点到汇点有多少条完全不同的最短路;每条边只能走一次。
题解:先SPFA求出源点到其他点的最短路,再用处于最短路上的边建图,容量1;
#include <iostream> #include <queue> #include <vector> using namespace std; const int inf=0x3f3f3f3f; struct rec { int u,v,w,link; }edge[300005]; struct re { int v,c; }; vector<re> E[1005]; bool vis[1005]; int head[1005],pre[1005],cur[1005],dis[1005],gap[1005]; int n,m,num,st,ed; inline void addedge(int u,int v,int w) { edge[num].u=u; edge[num].v=v; edge[num].w=w; edge[num].link=head[u]; head[u]=num++; edge[num].u=v; edge[num].v=u; edge[num].w=0; edge[num].link=head[v]; head[v]=num++; } void SPFA() { int i,v,u; memset(vis,0,sizeof(vis)); for(i=1;i<=n;i++) dis[i]=inf; //初始化源点到i点的距离 queue<int> Q; dis[st]=0; Q.push(st); while(!Q.empty()) { u=Q.front(); Q.pop(); vis[u]=0; for(i=0;i<E[u].size();i++) { v=E[u][i].v; if(dis[v]>dis[u]+E[u][i].c) { dis[v]=dis[u]+E[u][i].c; if(!vis[v]) { vis[v]=1; Q.push(v); } } } } } int max_flow() { int i,k,u,v,aug=inf,ans=0; memset(dis,0,sizeof(dis)); memset(gap,0,sizeof(gap)); gap[0]=n; u=pre[st]=st; for(i=1;i<=n;i++) cur[i]=head[i]; while(dis[st]<n) { loop: for(i=cur[u];i;i=cur[u]=edge[i].link) //在u点找允许弧 { v=edge[i].v; if(dis[u]==dis[v]+1 && edge[i].w) //若找到 { pre[v]=u; u=v; if(aug>edge[i].w) aug=edge[i].w; if(v==ed) //若v点是汇点,修改网络 { for(u=pre[v];v!=st;v=u,u=pre[u]) { edge[cur[u]].w-=aug; edge[cur[u]^1].w+=aug; } ans+=aug; aug=inf; } goto loop; //继续向后找 } } k=n; for(i=head[u];i;i=edge[i].link) //找不到,就修改dis[u] { v=edge[i].v; if(k>dis[v] && edge[i].w) { cur[u]=i; k=dis[v]; } if(--gap[dis[u]]==0) break; gap[dis[u]=k+1]++; u=pre[u]; } return ans; } int main() { int T,i,j,u,v,c; re tmp; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(i=1;i<=n;i++) E[i].clear(); num=2; memset(head,0,sizeof(head)); for(i=1;i<=m;i++) { scanf("%d%d%d",&u,&v,&c); if(u==v) continue; tmp.v=v; tmp.c=c; E[u].push_back(tmp); } scanf("%d%d",&st,&ed); //源点,汇点 SPFA(); for(i=1;i<=n;i++) for(j=0;j<E[i].size();j++) if(dis[E[i][j].v]==dis[i]+E[i][j].c) //源点到i点最短距离dis[i]于dis[j]之差为两点权值(E[i][j].c),即建图 addedge(i,E[i][j].v,1); printf("%d/n",max_flow()); } return 0; }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值