P4701 粘骨牌
Genius_Star · · 题解
思路:
首先黑白染色,然后你会发现空的格子一定是黑子。
考虑一下移动的限制,因为一个
于是可以先建一个黑点的图,表示所有的移动操作,然后考虑那些特殊位置,不能漏出来等价于
直接跑 dinic 即可,时间复杂度为
完整代码:
#include<bits/stdc++.h>
#define ls(k) k << 1
#define rs(k) k << 1 | 1
#define fi first
#define se second
#define popcnt(x) __builtin_popcount(x)
#define open(s1, s2) freopen(s1, "r", stdin), freopen(s2, "w", stdout);
using namespace std;
typedef __int128 __;
typedef long double lb;
typedef double db;
typedef unsigned long long ull;
typedef long long ll;
const int N = 1.1e6 + 10, M = 1e7 + 10;
const int INF = 1e9;
inline ll read(){
ll x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){
if(c == '-')
f = -1;
c = getchar();
}
while(c >= '0' && c <= '9'){
x = (x << 1) + (x << 3) + (c ^ 48);
c = getchar();
}
return x * f;
}
inline void write(ll x){
if(x < 0){
putchar('-');
x = -x;
}
if(x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
namespace Dinic {
struct edge {
int v, c, lim, nxt;
} e[M];
int head[N], dep[N], now[N];
int s, t, node, idx = 1;
inline void add(int u, int v, int c) {
e[++idx] = {v, c, c, head[u]};
head[u] = idx;
}
inline void Add(int u, int v, int c) {
// cerr << "edge: " << u << ' ' << v << ' ' << c << '\n';
add(u, v, c);
add(v, u, 0);
}
inline bool bfs() {
memset(dep, 0, sizeof(int) * (node + 1));
queue<int> q;
q.push(s);
dep[s] = 1;
while(!q.empty()) {
int u = q.front();
q.pop();
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].v, c = e[i].c;
if(!dep[v] && c) {
dep[v] = dep[u] + 1;
q.push(v);
if(v == t)
return 1;
}
}
}
return 0;
}
inline ll dfs(int u, ll mf) {
if(u == t)
return mf;
ll sum = 0;
for(int i = now[u]; i; i = e[i].nxt) {
now[u] = i;
int v = e[i].v, c = e[i].c;
if(dep[v] == dep[u] + 1 && c) {
ll flow = dfs(v, min((ll)c, mf));
e[i].c -= flow;
e[i ^ 1].c += flow;
sum += flow;
mf -= flow;
if(!mf)
break;
}
}
if(!sum)
dep[u] = 0;
return sum;
}
inline ll dinic() {
ll ans = 0;
while(bfs()) {
memcpy(now, head, sizeof(int) * (node + 1));
ans += dfs(s, INF);
}
return ans;
}
}
int n, m, k, s, t;
int w[N], h[N];
bool vis[N];
inline int id(int i, int j){
return (i - 1) * m + j;
}
inline bool col(int i, int j){
return (i + j - 1) & 1;
}
inline void add(int x, int y, int c){
Dinic::Add(x, y, c);
Dinic::Add(y, x, c);
}
int main(){
n = read(), m = read(), k = read();
Dinic::t = t = Dinic::node = n * m + 1;
for(int i = 1; i <= (n * m - 1) >> 1; ++i)
w[i] = read();
while(k--){
int x = read(), y = read();
if(col(x, y))
vis[id(x, y)] = 1;
}
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= m; ++j){
h[id(i, j)] = read();
if(h[id(i, j)] == h[id(i, j - 1)] && j > 1){
if(col(i, j) && j > 2)
add(id(i, j), id(i, j - 2), w[h[id(i, j)]]);
if(!col(i, j) && j + 1 <= m)
add(id(i, j - 1), id(i, j + 1), w[h[id(i, j)]]);
}
if(h[id(i, j)] == h[id(i - 1, j)] && i > 1){
if(col(i, j) && i > 2)
add(id(i, j), id(i - 2, j), w[h[id(i, j)]]);
if(!col(i, j) && i + 1 <= n)
add(id(i - 1, j), id(i + 1, j), w[h[id(i, j)]]);
}
if(!h[id(i, j)])
s = id(i, j);
if(col(i, j) && vis[id(i, j)])
Dinic::Add(id(i, j), t, INF);
}
}
if(vis[s]){
puts("GG");
return 0;
}
Dinic::s = s;
write(Dinic::dinic());
return 0;
}