LOJ#6068. 「2017 山东一轮集训 Day4」棋盘 题解

题目链接

考虑把一段连续的空地缩起来,形成一些"行"和"列"。

考虑一个网络流模型。

S -> 行,流量无限制,费用 \(f(flow) = \frac{flow (flow+1)}{2}\) , 列 -> T , 流量无限制,费用 \(f(flow) = \frac{flow (flow+1)}{2}\)

对于每个非障碍点,所在行 -> 列,流量为 1 ,费用为 0。

至于这个 \(f(flow) = \frac{flow (flow+1)}{2}\) , 我们把它拆成一堆流量为 1 , 费用分别为 0,1,2,3,4,...,5 的边。

最后因为 S -> 行不会用超过这一"行"里的点数的流量,列 -> T 类似,所以我们只会连 \(\Theta (n^2)\) 条边。

然后直接増广即可,注意到询问很多,要从小到大排序之后增加流量。

复杂度 \(O(EK(n^2,n^2))\) , 实测 ZKW 跑的很慢,因为询问可以覆盖满 \(1\) \(\cdots\) \(n^2\),这时候显然比 EK 慢。

code :

#include <bits/stdc++.h>
using namespace std;
template <typename T> void read(T &x){
	static char ch; x = 0,ch = getchar();
	while (!isdigit(ch)) ch = getchar();
	while (isdigit(ch)) x = x * 10 + ch - '0',ch = getchar();
}
inline void write(int x){if (x > 9) write(x/10); putchar(x%10+'0'); }
inline bool Get(){
	static char ch; ch = getchar();
	while (ch != '#' && ch != '.') ch = getchar();
	return ch == '.';
}
const int N = 52,M = 10005,V = N * N * 2 + 5,E = (N * N * 3 + 5) << 1;
int To[E],Ne[E],Flow[E],Cost[E],He[V],Now[V],_ = 1;
inline void add(int x,int y,int flow,int cost){
	++_; To[_] = y,Flow[_] = flow,Cost[_] = cost,Ne[_] = He[x],He[x] = _;
	++_; To[_] = x,Flow[_] = 0,Cost[_] = -cost,Ne[_] = He[y],He[y] = _;
}
int n,mp[N][N],id1[N][N],id2[N][N];
int S,T,cntv,nowcost,dis[V]; bool inq[V]; queue<int>Q;
inline bool Spfa(){
	int i,x,y,p;
	for (i = 1; i <= cntv; ++i) dis[i] = 10000000; dis[S] = 0,Q.push(S),inq[S] = 1;
	while (!Q.empty()){
		x = Q.front(),Q.pop(),inq[x] = 0;
		for (p = He[x]; p ; p = Ne[p]) if (Flow[p] && dis[y=To[p]] > dis[x] + Cost[p]){
			dis[y] = dis[x] + Cost[p]; if (!inq[y]) inq[y] = 1,Q.push(y);
		}
	}
	return dis[T] < 10000000;
}
bool vis[V];
inline int DFS(int x,int flow){
	if (!flow) return 0;
	if (x == T){ vis[T] = 1; return flow; }
	if (vis[x]) return 0; vis[x] = 1;
	int rest = flow,y,p,f;
	for (p = Now[x]; p ; p = Ne[p]){
		Now[x] = p;
		if (Flow[p] && dis[y=To[p]] == dis[x] + Cost[p]){
			f = DFS(y,min(Flow[p],rest)),Flow[p] -= f,Flow[p^1] += f,rest -= f;
			if (!rest) return flow;
		}
	}
	return flow - rest;
}
inline void work(int f){
	int ff;
	while (f && Spfa()){
		memcpy(Now,He,cntv+1<<2),vis[T] = 1;
		while (f && vis[T]) memset(vis,0,cntv+1),ff = DFS(S,f),nowcost += ff * dis[T],f -= ff;
	}
}
int cnt[N*N*2];
struct Query{ int id,x; bool operator < (const Query w) const{ return x < w.x; } }ask[M]; int ans[M],m;
int main(){
	int i,j;
	read(n); for (i = 1; i <= n; ++i) for (j = 1; j <= n; ++j) mp[i][j] = Get(); 
	read(m); for (i = 1; i <= m; ++i) ask[i].id = i,read(ask[i].x); sort(ask+1,ask+m+1);
	S = 1,T = cntv = 2;
	for (i = 1; i <= n; ++i) for (j = 1; j <= n; ++j) if (mp[i][j]){
		id1[i][j] = id1[i-1][j] ? id1[i-1][j] : ++cntv;
		id2[i][j] = id2[i][j-1] ? id2[i][j-1] : ++cntv;
		add(S,id1[i][j],1,cnt[id1[i][j]]++);
		add(id2[i][j],T,1,cnt[id2[i][j]]++);
		add(id1[i][j],id2[i][j],1,0);
	}
	int nowf = 0;
	for (i = 1; i <= m; ++i) work(ask[i].x-nowf),nowf = ask[i].x,ans[ask[i].id] = nowcost;
	for (i = 1; i <= m; ++i) write(ans[i]),putchar('\n');
	return 0;
}
posted @ 2020-09-26 18:33  srf  阅读(123)  评论(0编辑  收藏  举报