此题的大意:给定一幅有向图,求起点到终点(都是固定的)的不同的最短路有多少条。不同的最短路是说不能有相同的边,顶点可以重复。并且图含有平行边。

  看了题以后,就想到暴力,但是暴力往往是不可取的。(暴力的最坏情况下的时间复杂度是O(n^3))。我说的暴力是求一次最短路以后,把最短路上的边全部去掉(权值设为INF)。

  最短路可以有很多条,但是最短路的值只有一个。根据这个,我们可以判断某条边是否在最短路上。

  建图(单向边),求最短路,起点就是输入的起点。枚举每一条边,如果满足dist[i]+Map[i][j]==dist[j],就建立一条权值为i,j之间长度等于最短边的边数。

  我的做法是在建正向图的时候,用数组en[][]记录两点之间的长度等于最短边的边数。

  看上去代码蛮长的,其实就2个模版,main()才是需要自己去写的。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = , M=, INF=;
int dist[N], Map[N][N], pre[N],en[N][N];
bool p[N];
void Dijkstra(int s,int n)
{
int i,j,k, MIN;
for(i=; i<=n; i++) //初始化
{
p[i]=;
if(i!=s)
{
dist[i]= Map[s][i];
pre[i]=s;
}
}
dist[s]=;
p[s]=;
for(i=; i<n; i++) //循环n-1次
{
MIN=INF;
k=;
for(j=; j<=n; j++)
{
if(!p[j]&&dist[j]<MIN)
{
MIN= dist[j];
k=j;
}
}
if(!k) return ;//没有点可以扩展
p[k]=; //将k从Vb中除去,加入Va
for(j=; j<=n; j++)
{
if(!p[j]&&Map[k][j]!=INF&&dist[j]>dist[k]+Map[k][j])
{
dist[j]= dist[k] + Map[k][j];
pre[j]=k;
}
}
}
}
struct node
{
int to,next,w;
}edge[M];
int head[N],numh[N],h[N],cure[N];
int ans,tot;
void SAP(int s, int e,int n)
{
int flow,u,tmp,neck,i;
ans=;
for(i=;i<=n;i++)
cure[i]=head[i];
numh[]=n;
u=s;
while(h[s]<n)
{
if(u==e)
{
flow =INF;
for(i=s;i!=e;i=edge[cure[i]].to)
{
if(flow>edge[cure[i]].w)
{
neck=i;
flow =edge[cure[i]].w;
}
}
for(i=s;i!=e;i=edge[cure[i]].to)
{
tmp=cure[i];
edge[tmp].w-=flow;
edge[tmp^].w+=flow;
}
ans+=flow;
u=neck;
}
for(i=cure[u];i!=-;i=edge[i].next)
if(edge[i].w && h[u]==h[edge[i].to]+) break;
if(i!=-) {cure[u]=i;pre[edge[i].to]=u;u=edge[i].to;}
else
{
if(==--numh[h[u]]) break; //GAP优化
cure[u]=head[u];
for(tmp=n,i=head[u];i!=-;i=edge[i].next)
if(edge[i].w) tmp=min(tmp, h[edge[i].to]);
h[u]=tmp+;
++numh[h[u]];
if(u!=s) u=pre[u];
}
}
}
void init()
{
tot=;
memset(head,-,sizeof(head));
memset(pre,-,sizeof(pre));
memset(h,,sizeof(h));
memset(numh,,sizeof(numh)); }
void addedge(int i,int j,int w)
{
edge[tot].to=j;edge[tot].w=w;edge[tot].next=head[i];head[i]=tot++;
edge[tot].to=i;edge[tot].w=;edge[tot].next=head[j];head[j]=tot++;
}
int main()
{
//freopen("test.txt","r",stdin);
int n,m,i,j,k,s,e,cas;
scanf("%d",&cas);
while(cas--)
{
scanf("%d%d",&n,&m);
for(i=;i<=n;i++)
for(j=;j<=n;j++)
{
Map[i][j]=INF;
en[i][j]=;
}
while(m--)
{
scanf("%d%d%d",&i,&j,&k);
if(i==j) continue;
if(Map[i][j]>k) {Map[i][j]=k, en[i][j]=;}
else if (Map[i][j]==k) {en[i][j]++;}
}
scanf("%d%d",&s,&e);
Dijkstra(s,n);
init();
for(i=;i<=n;i++)
{
for(j=;j<=n;j++)
{
if(Map[i][j]!=INF)
{
if(dist[i]+Map[i][j]==dist[j])
addedge(i,j,en[i][j]);
}
}
}
SAP(s,e,n);
printf("%d\n",ans);
}
return ;
}

hdu3416 Marriage Match IV 最短路+ 最大流的更多相关文章

  1. HDU-3416 Marriage Match IV 最短路+最大流 找各最短路的所有边

    题目链接:https://cn.vjudge.net/problem/HDU-3416 题意 给一个图,求AB间最短路的条数(每一条最短路没有重边.可有重复节点) 思路 首先把全部最短路的边找出来,再 ...

  2. HDU3416 Marriage Match IV —— 最短路径 + 最大流

    题目链接:https://vjudge.net/problem/HDU-3416 Marriage Match IV Time Limit: 2000/1000 MS (Java/Others)    ...

  3. Marriage Match IV(最短路+网络流)

    Marriage Match IV http://acm.hdu.edu.cn/showproblem.php?pid=3416 Time Limit: 2000/1000 MS (Java/Othe ...

  4. hdu3416 Marriage Match IV【最短路+最大流】

    转载请注明出处,谢谢:http://www.cnblogs.com/KirisameMarisa/p/4297581.html   ---by 墨染之樱花 题目链接:http://acm.hdu.ed ...

  5. hdu3416 Marriage Match IV(最短路+网络流)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3416 题意: 给出含n个点.m条有向边的图,每条边只能走一次,给出起点和终点,求起点到终点的最短路径有 ...

  6. HDU 3416 Marriage Match IV (最短路建图+最大流)

    (点击此处查看原题) 题目分析 题意:给出一个有n个结点,m条单向边的有向图,问从源点s到汇点t的不重合的最短路有多少条,所谓不重复,意思是任意两条最短路径都不共用一条边,而且任意两点之间的边只会用一 ...

  7. HDU 3416 Marriage Match IV (Dijkstra+最大流)

    题意:N个点M条边的有向图,给定起点S和终点T,求每条边都不重复的S-->T的最短路有多少条. 分析:首先第一步需要找出所有可能最短路上的边.怎么高效地求出呢?可以这样:先对起点S,跑出最短路: ...

  8. hdu3461Marriage Match IV 最短路+最大流

    //给一个图.给定起点和终点,仅仅能走图上的最短路 //问最多有多少种走的方法.每条路仅仅能走一次 //仅仅要将在最短路上的全部边的权值改为1.求一个最大流即可 #include<cstdio& ...

  9. HDU 3416 Marriage Match IV (最短路径&&最大流)

    /*题意: 有 n 个城市,知道了起点和终点,有 m 条有向边,问从起点到终点的最短路一共有多少条.这是一个有向图,建边的时候要注意!!解题思路:这题的关键就是找到哪些边可以构成最短路,其实之前做最短 ...

随机推荐

  1. 通过yum仓库安装mysql

    1,下载安装包wget http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm2,安装mysql源yum -y ins ...

  2. 【转】上拉下拉电阻、I/O输出(开漏、推挽等)

    作者:BakerZhang 链接:https://www.jianshu.com/p/3ac3a29b0f58来源:简书 感谢! ——————————————————————————————————— ...

  3. Package和Activity

    Package Package 包.只是在我们的app中这个Package是唯一的,就像你身份证号码一样.在我们做app自动化时,我们就需要知道他的Package,我们知道了Package那么也就知道 ...

  4. 【Shell编程】Shell基本语法

    Shell 语法   Shell程序设计作为一种脚本语言,在Linux系统中有广泛的应用,本文记录了关于Shell程序设计的基础语法知识和常用命令,方便查询,熟练使用shell也需要经常实践,这对于完 ...

  5. 八进制、十进制、操作符(day04)

    把二进制表示的数字从右向左每三个数位分成 一组,每组用一个0到7之间的数字替换. 这个替换结果叫做数字的八进制表示方式 (八进制) 可以直接在程序里用八进制方式表示数字, 这种数字必须以0做开头 可以 ...

  6. 程序包管理rpm和yum

    Linux程序包管理: API:Application Programming Interface源码包 POSIX:Portable OS 程序源代码 --> 预处理 --> 编译 -- ...

  7. SIM300命令参考

    开机命令   AT+CFUN=1,1          //此命令可以开启simcom模块的大部分功能,一般在初始化模块的时候都要写上: AT&F                        ...

  8. [bzoj4196][Noi2015]软件包管理器_树链剖分_线段树

    软件包管理器 bzoj-4196 Noi-2015 题目大意:Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件 ...

  9. 洛谷—— P2647 最大收益

    https://www.luogu.org/problem/show?pid=2647 题目描述 现在你面前有n个物品,编号分别为1,2,3,……,n.你可以在这当中任意选择任意多个物品.其中第i个物 ...

  10. Android开发时经经常使用的LogUtil

    在开发过程中经经常使用到Log.我们常写的一种方式就是自己定义一个LogUtil工具类 private static boolean LOGV = true; private static boole ...