Loading

P5331 [SNOI2019]通信 题解

本来以为要优化建图,但直接用zkw费用流艹过去了。

思路

大概是一个一眼网络流。

首先考虑建图。

通用模型,首先进行拆点,建立超级源点和超级汇点。

下文拆出的两个点一个叫点,一个叫次点。

源点向每一个点连一个流量为一,费用为零的边。

要注意,题目中所说的为直接连接到控制中心或者连接到前面的某个哨站。

所以次点向汇点连得边费用为零,流量为一(开始没想明白,样例都过不了)。

同时,每个点向汇点连一条流量为一,费用为 \(w\) 的边。

做法

我们可以发现,边数极其的多,普通的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;
}


完结撒花!

posted @ 2021-11-17 14:16  JiaY19  阅读(62)  评论(1编辑  收藏  举报