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;
}