题目

给出一个 $n$ 个顶点 $m$ 条边的图,要求阻塞一些边,使得从 $1$ 到 $n$ 的最短路变长,求阻塞的边长度和的最小值,不必保证阻塞后可达。

分析

很显然,要阻塞的边肯定在最短路图上,先跑一遍单源最短路,求出最短路图。

要使最短路变长,肯定要同时切断原有的所有最短路,又要是长度(相当于流量)和最小,很容易想到就是求最小割。

简而言之,就是在最短路图上求最小割。

两个模板拼起来就好了(难得写抄这么长的能一遍AC)

#include<bits/stdc++.h>
using namespace std; typedef long long ll;
const ll INF = 1ll << ;
const int INF2 = 0x3f3f3f3f;
const int maxv = +; //最大顶点数
const int maxn = maxv;
const int maxe = +; //最大边数
ll dis[maxv];
int cnt[maxv];
bool inq[maxv]; //记录是否在队中
int head[maxv], id; //head2[maxv], cnt2;
int n, m; struct Edge
{
int to, w, next;
}edge[maxe]; inline void init()
{
memset(head, -, sizeof(head));
id=;
} inline void addedge(int u, int v, int w, int id)
{
edge[id].to = v;
edge[id].w = w;
edge[id].next = head[u];
head[u] = id;
} bool SPFA(int s)
{
deque<int>q;
memset(inq, false, sizeof(inq));
memset(cnt, , sizeof(cnt));
for (int i = ; i <= n; i++) dis[i] = INF;
dis[s] = ;
inq[s] = true;
q.push_back(s); while (!q.empty())
{
int u = q.front(); q.pop_front();
inq[u] = false;
for (int i = head[u]; i != -; i = edge[i].next)
{
int v = edge[i].to, w = edge[i].w;
if (dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
if (!inq[v])
{
inq[v] = true;
//SLF优化
q.push_back(v);
if (++cnt[v] > n) return false;
if (dis[q.back()] < dis[q.front()])
{
int k = q.back();
q.pop_back();
q.push_front(k);
}
}
}
}
}
return true;
} struct Edge2{
int from, to, cap, flow;
Edge2(int u, int v, int c, int f):from(u), to(v), cap(c), flow(f){}
};
struct EdmondsKarp{
int n, m;
vector<Edge2>edges; //边数的两倍
vector<int>G[maxn]; //邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
int a[maxn]; //当起点到i的可改进量
int p[maxn]; //最短树上p的入弧编号 void init(int n)
{
for(int i = ;i <= n;i++) G[i].clear();
edges.clear();
} void AddEdge(int from, int to, int cap)
{
edges.push_back(Edge2(from, to, cap, ));
edges.push_back(Edge2(to, from, , ));
m = edges.size();
G[from].push_back(m-);
G[to].push_back(m-);
} ll Maxflow(int s, int t)
{
ll flow = ;
for(;;)
{
memset(a, , sizeof(a));
queue<int>Q;
Q.push(s);
a[s] = INF2;
while(!Q.empty())
{
int x = Q.front(); Q.pop();
for(int i = ;i < G[x].size();i++)
{
Edge2& e = edges[G[x][i]];
if(!a[e.to] && e.cap > e.flow)
{
p[e.to] = G[x][i];
a[e.to] = min(a[x], e.cap-e.flow);
Q.push(e.to);
}
}
if(a[t]) break;
}
if(!a[t]) break;
for(int u = t; u != s;u=edges[p[u]].from)
{
edges[p[u]].flow += a[t];
edges[p[u]^].flow -= a[t];
}
flow += a[t];
}
return flow;
}
}ek; int main()
{
int T;
scanf("%d", &T);
while(T--)
{
init();
scanf("%d%d", &n, &m);
for(int i = ;i < m;i++)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
addedge(u, v, w, id++);
}
SPFA();
ek.init(n);
for(int i = ;i <= n;i++)
{
for(int j = head[i]; j != -;j = edge[j].next)
{
int v = edge[j].to, w = edge[j].w;
if(dis[v]-dis[i] == w)
ek.AddEdge(i, v, w);
}
}
printf("%lld\n", ek.Maxflow(, n));
}
return ;
}

参考链接:https://blog.csdn.net/lgz0921/article/details/96891132#comments

最新文章

  1. 五个典型的 JavaScript 面试题
  2. 第一天 :学习node.js
  3. js 中 == 和=== 有什么区别?
  4. mysql linux终端登陆
  5. postfix之dovecot
  6. chrome控制台小技巧
  7. MySQL &#183; 引擎特性 &#183; InnoDB COUNT(*) 优化(?)
  8. 解析sql中的表名
  9. SQLServer Alter 修改表的列名的解决
  10. study notes: high performance linux server programming
  11. c#基础练习之if结构
  12. oracle_数据库访问问题
  13. dubbo源码—Service Reply
  14. 【BZOJ3991】【SDOI2015】寻宝游戏
  15. LOJ 2483: 洛谷 P4655: 「CEOI2017」Building Bridges
  16. C#如何通过反射调用类下的方法
  17. 读取properties文件的信息
  18. Mysql命令行改动字段类型
  19. windows 7 Alt+Tab 的风格改成 XP 风格
  20. 常见的web负载均衡方法总结

热门文章

  1. java源码 -- TreeMap
  2. 【C++札记】new和delete
  3. 创客课堂——Scratch的操作界面
  4. Once in a casino CodeForces - 1120B (暴力)
  5. 应用人员反馈报错,ORA-03137: TTC protocol internal error : [12333]
  6. hdu 6165
  7. (一)easyUI之第一个demo
  8. (二十五)JSP九大内置对象(转)
  9. (一)shiro简介和用户登录demo及角色管理
  10. Entity Framewrok Migration 重置