分析:ios
首先將每一個整張圖按行和列分連通塊,兩個'#'之間算一個連通塊。每一個空點只能屬於個行連通塊和列連通塊,從行連通塊向列連通塊連邊,容量爲1,費用爲0。若是這條邊走了1的流量,就說明這個點選了,考慮這個點選了後的花費。git
若是這個點是他屬於的行連通塊中的第一個點,那麼費用爲0,若是是第二個,那麼費用爲1...ui
因而S向行連通塊連連通塊連siz條邊,費用分別是0,1,2...siz-1。預處理答案,每次增長一個點,即增長一的總容量,跑費用流。spa
代碼:code
#include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #include<cmath> #include<cctype> #include<set> #include<queue> #include<vector> #include<map> #include<bitset> #define fore(i, u, v) for (int i = head[u], v = e[i].to; i; i = e[i].nxt, v = e[i].to) using namespace std; typedef long long LL; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; } const int INF = 1e9, N = 160005; struct Edge { int from, to, nxt, cap, cost; } e[N << 1]; int head[N], dis[N], pre[N], siz[N], bel[55][55], bel2[55][55], q[N], ans[N]; bool vis[N]; char s[55][55]; int En = 1, S, T, TT; inline void add_edge(int u,int v,int f,int w) { ++En; e[En] = (Edge){u, v, head[u], f, w}; head[u] = En; ++En; e[En] = (Edge){v, u, head[v], 0, -w}; head[v] = En; } bool spfa() { for (int i = 0; i <= TT; ++i) dis[i] = INF, vis[i] = pre[i] = 0; int L = 1, R = 0; q[++R] = S; dis[S] = 0, vis[S] = 1; while (L <= R) { int u = q[L ++]; vis[u] = 0; fore(i, u, v) if (dis[v] > dis[u] + e[i].cost && e[i].cap > 0) { dis[v] = dis[u] + e[i].cost, pre[v] = i; if (!vis[v]) q[++R] = v, vis[v] = 1; } } return dis[TT] != INF; } int mcf() { spfa(); int Flow = INF; for (int i = TT; i != S; i = e[pre[i]].from) Flow = min(Flow, e[pre[i]].cap); for (int i = TT; i != S; i = e[pre[i]].from) e[pre[i]].cap -= Flow, e[pre[i] ^ 1].cap += Flow; return Flow * dis[TT]; } int main() { int n = read(), sum = 0, cnt = 0, tmp; for (int i = 1; i <= n; ++i) { scanf("%s", s[i] + 1); for (int j = 1; j <= n; ++j) sum += s[i][j] == '.'; } for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) { if (j == 1 || s[i][j - 1] == '#') cnt ++; bel[i][j] = cnt; siz[cnt] ++; } tmp = cnt; for (int j = 1; j <= n; ++j) for (int i = 1; i <= n; ++i) { if (i == 1 || s[i - 1][j] == '#') cnt ++; bel2[i][j] = cnt; siz[cnt] ++; } S = 0, T = cnt + 1, TT = T + 1; for (int i = 1; i <= tmp; ++i) { add_edge(S, i, 1, 0); for (int j = 1; j < siz[i]; ++j) add_edge(S, i, 1, j); } for (int i = tmp + 1; i <= cnt; ++i) { add_edge(i, T, 1, 0); for (int j = 1; j < siz[i]; ++j) add_edge(i, T, 1, j); } for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) if (s[i][j] == '.') add_edge(bel[i][j], bel2[i][j], 1, 0); for (int i = 1; i <= sum; ++i) { add_edge(T, TT, 1, 0); ans[i] = ans[i - 1] + mcf(); } for (int m = read(); m --; ) printf("%d\n", ans[read()]); return 0; }