Marriage Match IV

HDOJ-3416

  • 这题的题意就是要找两点之间最短路的路径个数,而且边不能重复。
  • 最大流和最短路的结合。首先正向和反向建图,再跑两遍dijikstra。到这里就求出来起点到某一点的最短路以及某一点到终点的最短路。
  • 还有一个关键的公式就是如何判断一条边是否在最短路中:如果起点到该边的起点的最短距离加上该边的终点到终点的最短距离再加上该边的长度等于起点到终点的最短路,那该边就在最短路中。
  • 还有一个需要注意的地方就是最大流算法的选用,如果需用EK算法,时间复杂度和边数成2次方关系。所以,这里选用ISAP高级算法。但也给出EK算法的求解过程。

ISAP算法

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int INF=0X3F3F3F3F;
const int maxn=1003;
const int maxm=100005;
int n,m;
int map[maxn][maxn];
int d[2][maxn];//最短路
int st,ed;
struct Edge {
int from, to, cap, flow;
Edge(int u, int v, int c, int f) : from(u), to(v), cap(c), flow(f) {}
}; bool operator<(const Edge& a, const Edge& b) {
return a.from < b.from || (a.from == b.from && a.to < b.to);
} struct ISAP {
int n, m, s, t;
vector<Edge> edges;
vector<int> G[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
int p[maxn];
int num[maxn]; void AddEdge(int from, int to, int cap) {
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, 0, 0));
m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
} bool BFS() {
memset(vis, 0, sizeof(vis));
queue<int> Q;
Q.push(t);
vis[t] = 1;
d[t] = 0;
while (!Q.empty()) {
int x = Q.front();
Q.pop();
for (int i = 0; i < G[x].size(); i++) {
Edge& e = edges[G[x][i] ^ 1];
if (!vis[e.from] && e.cap > e.flow) {
vis[e.from] = 1;
d[e.from] = d[x] + 1;
Q.push(e.from);
}
}
}
return vis[s];
} void init(int n) {
this->n = n;
for (int i = 0; i < n; i++) G[i].clear();
edges.clear();
} int Augment() {
int x = t, a = INF;
while (x != s) {
Edge& e = edges[p[x]];
a = min(a, e.cap - e.flow);
x = edges[p[x]].from;
}
x = t;
while (x != s) {
edges[p[x]].flow += a;
edges[p[x] ^ 1].flow -= a;
x = edges[p[x]].from;
}
return a;
} int Maxflow(int s, int t) {
this->s = s;
this->t = t;
int flow = 0;
BFS();
memset(num, 0, sizeof(num));
for (int i = 0; i < n; i++) num[d[i]]++;
int x = s;
memset(cur, 0, sizeof(cur));
while (d[s] < n) {
if (x == t) {
flow += Augment();
x = s;
}
int ok = 0;
for (int i = cur[x]; i < G[x].size(); i++) {
Edge& e = edges[G[x][i]];
if (e.cap > e.flow && d[x] == d[e.to] + 1) {
ok = 1;
p[e.to] = G[x][i];
cur[x] = i;
x = e.to;
break;
}
}
if (!ok) {
int m = n - 1;
for (int i = 0; i < G[x].size(); i++) {
Edge& e = edges[G[x][i]];
if (e.cap > e.flow) m = min(m, d[e.to]);
}
if (--num[d[x]] == 0) break;
num[d[x] = m + 1]++;
cur[x] = 0;
if (x != s) x = edges[p[x]].from;
}
}
return flow;
}
}ek;
struct edge{
int to;
int cost;
int next;
};
int head[maxn];
int heads[maxn];
edge ma[maxm];
edge mas[maxm];
struct node{
int dis;
int to;
bool operator<(const node& t)const{
return dis>t.dis;
}
};
void dijikstra(int s,int f,int *head,edge ma[]){
for(int i=1;i<=n;i++){
d[f][i]=INF;
}
d[f][s]=0;
priority_queue<node> q;
q.push({0,s});
while(!q.empty()){
node now=q.top();
q.pop();
int v=now.to;
int dis=now.dis;
if(d[f][v]<dis){
continue;
}
for(int i=head[v];i!=-1;i=ma[i].next){
int u=ma[i].to;
//cout<<u<<endl;
int cost=ma[i].cost;
if(d[f][u]>d[f][v]+cost){
d[f][u]=d[f][v]+cost;
q.push({d[f][u],u});
}
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while(t--){
cin>>n>>m;
memset(head,-1,sizeof(head));
memset(heads,-1,sizeof(heads));
for(int i=0;i<m;i++){
int a,b,c;
cin>>a>>b>>c;
if(a==b)
continue;
ma[i].to=b;
ma[i].cost=c;
ma[i].next=head[a];
head[a]=i; mas[i].to=a;
mas[i].cost=c;
mas[i].next=heads[b];
heads[b]=i;
}
cin>>st>>ed;
dijikstra(st,0,head,ma);
dijikstra(ed,1,heads,mas);
//cout<<d[0][ed]<<endl;
//cout<<d[1][st]<<endl;
int final=d[0][ed];
if(final==INF){
cout<<0<<endl;
continue;
}
ek.init(n);
for(int i=1;i<=n;i++){
for(int j=head[i];j!=-1;j=ma[j].next){
if(d[0][i]+d[1][ma[j].to]+ma[j].cost==final)
ek.AddEdge(i,ma[j].to,1);
}
}
cout<<ek.Maxflow(st,ed)<<endl;
}
return 0;
}

EK算法

struct edge{
int to;
int cost;
int next;
};
int head[maxn];
int heads[maxn];
edge ma[maxm];
edge mas[maxm];
struct node{
int dis;
int to;
bool operator<(const node& t)const{
return dis>t.dis;
}
};
void dijikstra(int s,int f,int *head,edge ma[]){
for(int i=1;i<=n;i++){
d[f][i]=INF;
}
d[f][s]=0;
priority_queue<node> q;
q.push({0,s});
while(!q.empty()){
node now=q.top();
q.pop();
int v=now.to;
int dis=now.dis;
if(d[f][v]<dis){
continue;
}
for(int i=head[v];i!=-1;i=ma[i].next){
int u=ma[i].to;
//cout<<u<<endl;
int cost=ma[i].cost;
if(d[f][u]>d[f][v]+cost){
d[f][u]=d[f][v]+cost;
q.push({d[f][u],u});
}
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while(t--){
cin>>n>>m;
memset(head,-1,sizeof(head));
memset(heads,-1,sizeof(heads));
for(int i=0;i<m;i++){
int a,b,c;
cin>>a>>b>>c;
if(a==b)
continue;
ma[i].to=b;
ma[i].cost=c;
ma[i].next=head[a];
head[a]=i; mas[i].to=a;
mas[i].cost=c;
mas[i].next=heads[b];
heads[b]=i;
}
cin>>st>>ed;
dijikstra(st,0,head,ma);
dijikstra(ed,1,heads,mas);
//cout<<d[0][ed]<<endl;
//cout<<d[1][st]<<endl;
int final=d[0][ed];
if(final==INF){
cout<<0<<endl;
continue;
}
ek.init(n);
for(int i=1;i<=n;i++){
for(int j=head[i];j!=-1;j=ma[j].next){
if(d[0][i]+d[1][ma[j].to]+ma[j].cost==final)
ek.AddEdge(i,ma[j].to,1);
}
}
cout<<ek.Maxflow(st,ed)<<endl;
}
return 0;
}

HDOJ-3416(最大流+最短路+ISAP算法+向前星dijikstra算法+如何判断一条边是否在最短路中)的更多相关文章

  1. 模板——最小生成树prim算法&&向前星理解

    通过最小生成树(prim)和最短路径优化引出的向前星存图,时至今日才彻底明白了.. head[i]存储的是父节点为i引出的最后一条边的编号, next负责把head[i]也就是i作为父节点的所有边连接 ...

  2. 笔试算法题(19):判断两条单向链表的公共节点 & 字符集删除函数

    出题:给定两个单向链表的头结点,判断其是否有公共节点并确定第一个公共节点的索引: 分析: 由于是单向链表,所以每个节点有且仅有一个后续节点,所以只可能是Y型交叉(每条链表中的某个节点同时指向一个公共节 ...

  3. HDU 3416 Marriage Match IV(ISAP+最短路)题解

    题意:从A走到B,有最短路,问这样不重复的最短路有几条 思路:先来讲选有效边,我们从start和end各跑一次最短路,得到dis1和dis2数组,如果dis1[u] + dis2[v] + cost[ ...

  4. poj-1459-最大流dinic+链式前向星-isap+bfs+stack

    title: poj-1459-最大流dinic+链式前向星-isap+bfs+stack date: 2018-11-22 20:57:54 tags: acm 刷题 categories: ACM ...

  5. 【模板】 最大流模板(ISAP)

    题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行 ...

  6. 最大流算法之Ford-Fulkerson算法与Edmonds–Karp算法

    引子 曾经很多次看过最大流的模板,基础概念什么的也看了很多遍.也曾经用过强者同学的板子,然而却一直不会网络流.虽然曾经尝试过写,然而即使最简单的一种算法也没有写成功过,然后对着强者大神的代码一点一点的 ...

  7. coding++:RateLimiter 限流算法之漏桶算法、令牌桶算法--简介

    RateLimiter是Guava的concurrent包下的一个用于限制访问频率的类 <dependency> <groupId>com.google.guava</g ...

  8. 【算法•日更•第三十五期】FF算法优化:EK算法

    ▎写在前面 FF算法传送门 之前我们已经学过了FF算法(全称Ford-Fulkerson算法)来找最大流,但是这种算法仍有诸多不对的地方. 其实这种算法存在着严重的效率的问题,请看下面的图: 以这个图 ...

  9. 最短路径算法之二——Dijkstra算法

    Dijkstra算法 Dijkstra算法主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止. 注意该算法要求图中不存在负权边. 首先我们来定义一个二维数组Edge[MAXN][MAXN]来存储 ...

随机推荐

  1. 二分图最大权匹配问题&&KM算法讲解 && HDU 2255 奔小康赚大钱

    作者:logosG 链接:https://www.cnblogs.com/logosG/p/logos.html (讲解的KM算法,特别厉害!!!) KM算法: 现在我们来考虑另外一个问题:如果每个员 ...

  2. 一个方便 LeetCode 复习的脚本

    这个脚本半年前就在用了,只不过一直没有公开. 这是一个简易的 LeetCode 自动统计程序, 可自动统计最近提交通过的题目, 并以 Markdown 的形式展示相关的数据. 采用 GitHub Ac ...

  3. WPF 之命令(七)

    一.前言 ​ 事件的作用是发布和传播一些消息,消息送达接收者,事件的使命也就完成了,至于消息响应者如何处理发送来的消息并不做规定,每个接收者可以使用自己的行为来响应事件.即事件不具有约束力. ​ 命令 ...

  4. 详解Go语言I/O多路复用netpoller模型

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com 本文使用的go的源码15.7 可以从 Go 源码目录结构和对应代码文件了解 Go 在不同 ...

  5. 使用dotNET_Reactor4.7加密后的dll在VS2010中无法打包

    1.只要去除加密工具中的反编译选项"Anti ILDASM",再加密就OK了. 2.或者使用VS2008打包也行.

  6. 微服务架构Day02-SpringBoot日志slf4j

    日志框架 日志门面(接口,日志抽象层 ) 日志实现 JCL(Jakarta Commons Logging).slf4j(Simple Logging Facade for Java).jboss-l ...

  7. 缓冲区溢出实验 5 Snprintf

    实验环境.代码.及准备 https://www.cnblogs.com/lqerio/p/12870834.html vul5 Snprintf函数,百度百科: 将可变个参数(...)按照format ...

  8. redis键过期时间

    redis服务器中每个数据库都是一个redisDb,而redisDb实质上是一个字典的模型,数据库的每一个键都是一个字典的键值,对数据库的增删改查也就是对字典对象的增删改查. redis在维护带有过期 ...

  9. set CSS style in js solutions All In One

    set CSS style in js solutions All In One css in js set each style property separately See the Pen se ...

  10. how to read the system information by using the node cli tool?

    how to read the system information by using the node cli tool? node cli & get system info demos ...