P5331 [SNOI2019]通信 题解
本来以为要优化建图,但直接用zkw费用流艹过去了。
思路#
大概是一个一眼网络流。
首先考虑建图。
通用模型,首先进行拆点,建立超级源点和超级汇点。
下文拆出的两个点一个叫点,一个叫次点。
源点向每一个点连一个流量为一,费用为零的边。
要注意,题目中所说的为直接连接到控制中心或者连接到前面的某个哨站。
所以次点向汇点连得边费用为零,流量为一(开始没想明白,样例都过不了)。
同时,每个点向汇点连一条流量为一,费用为
做法#
我们可以发现,边数极其的多,普通的MCMF跑不过去,这里介绍一种更快的费用流方法zkw费用流,也就是多路增广的费用流算法。
zkw费用流#
与普通费用流算法不同的是,zkw费用流在进行SPFA时,需要进行分层。
为多路增广做准备。
dfs和zkw部分与普通的dinic相差无几,具体细节可以看代码。
Code#
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int inf = 1e18;
int n , w , s , t , cnt = 1 , a[1010] , head[2020];
int maxflow , ans , dis[2020] , dep[2020] , vis[2020] , gap[2020];
inline int read()
{
int asd = 0 , qwe = 1; char zxc;
while(!isdigit(zxc = getchar())) if(zxc == '-') qwe = -1;
while(isdigit(zxc)) asd = asd * 10 + zxc - '0' , zxc = getchar();
return asd * qwe;
}
struct edge
{
int to , nxt , val , cost;
} e[8000010];
inline void add(int x , int y , int z , int u)
{
e[++cnt] = (edge){y , head[x] , z , u} , head[x] = cnt;
e[++cnt] = (edge){x , head[y] , 0 , -u} , head[y] = cnt;
}
inline bool spfa()
{
memset(vis , 0 , sizeof(vis));
memset(dep , 0 , sizeof(dep));
for(int i = 1;i <= 2 * n + 2;i++) dis[i] = inf;
dis[s] = 0 , dep[s] = 1 , vis[s] = 1;
deque<int> q; q.push_back(s);
while(q.empty() == 0)
{
int x = q.front();
q.pop_front() , vis[x] = 0;
for(int i = head[x];i;i = e[i].nxt)
{
int y = e[i].to;
if(dis[y] > dis[x] + e[i].cost && e[i].val > 0)
{
dis[y] = dis[x] + e[i].cost , dep[y] = dep[x] + 1;
if(vis[y] == 0)
{
vis[y] = 1;
if(q.empty() == 0 && dis[y] < dis[q.front()]) q.push_front(y);
else q.push_back(y);
}
}
}
}
return dis[t] != inf;
}
bool flag;
inline int dfs(int now , int flow)
{
if(now == t)
{
maxflow += flow , flag = 1;
return flow;
}
int used = 0;
for(int i = head[now];i;i = e[i].nxt)
{
int y = e[i].to;
if(dis[now] + e[i].cost == dis[y] && dep[now] + 1 == dep[y] && e[i].val > 0)
{
int sum = dfs(y , min(e[i].val , flow - used));
used += sum , e[i].val -= sum , e[i ^ 1].val += sum , ans += sum * e[i].cost;
if(used == flow) return used;
}
}
return used;
}
inline void zkw()
{
while(spfa())
{
flag = 1;
while(flag) flag = 0 , dfs(s , inf);
}
cout << ans;
}
signed main()
{
n = read() , w = read() , s = 2 * n + 1 , t = 2 * n + 2;
for(int i = 1;i <= n;i++) a[i] = read();
for(int i = 1;i <= n;i++) add(s , i , 1 , 0),
for(int i = 1;i <= n;i++) add(i , t , 1 , w) , add(n + i , t , 1 , 0);
for(int i = 1;i <= n;i++)
for(int j = i + 1;j <= n;j++)
if(abs(a[i] - a[j]) < w) add(j , n + i , 1 , abs(a[i] - a[j]));
zkw();
return 0;
}
完结撒花!
作者:JiaY19
出处:https://www.cnblogs.com/JiaY19/p/15567066.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)