P3965 [TJOI2013] 循环格
Genius_Star · · 题解
思路:
首先显然每个点出度为
所以图由若干个互不相交的环构成,那么所有点入度也为
为了确保出入度平衡,将每个点拆为左右两个点:
-
初始源点向左部点建流量为
1 费用为0 的边,右部点向汇点建立流量为1 费用为0 的边(意思是从这个点出去的流量“出度”最后一定会走一个循环回来“入度”)。 -
对于这个点本来指向的边,直接左部点向这个指向的点的右部点建立流量为
1 费用为0 。 -
对于其它三个没指向的边,建立流量为
1 费用为1 的边。
显然此时最大流为
时间复杂度为
完整代码:
#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 = 505, M = 1e5 + 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 MCMF {
struct edge {
int v, c, w, nxt;
} e[M];
int s, t, node, idx = 1;
int head[N], now[N];
ll dis[N];
bool vis[N];
inline void add(int u, int v, int c, int w){
e[++idx] = {v, c, w, head[u]};
head[u] = idx;
}
inline void Add(int u, int v, int c, int w){
// cerr << "edge: " << u << ' ' << v << ' ' << c << ' ' << w << '\n';
add(u, v, c, w);
add(v, u, 0, -w);
}
inline bool spfa(){
for(int i = 0; i <= node; ++i)
dis[i] = INF;
deque<int> q;
q.push_front(s);
dis[s] = 0, vis[s] = 1;
while(!q.empty()){
int u = q.front();
q.pop_front();
vis[u] = 0;
for(int i = head[u]; i; i = e[i].nxt){
int v = e[i].v, c = e[i].c, w = e[i].w;
if(dis[v] > dis[u] + w && c){
dis[v] = dis[u] + w;
if(!vis[v]){
if(!q.empty() && dis[v] > dis[q.front()])
q.push_back(v);
else
q.push_front(v);
vis[v] = 1;
}
}
}
}
return dis[t] != INF;
}
inline ll dfs(int u, ll mf, ll &ans){
if(u == t)
return mf;
vis[u] = 1;
ll sum = 0;
for(int i = now[u]; i && mf; i = e[i].nxt){
now[u] = i;
int v = e[i].v, c = e[i].c, w = e[i].w;
if(!vis[v] && dis[v] == dis[u] + w && c){
ll flow = dfs(v, min((ll)c, mf), ans);
if(!flow)
dis[v] = INF;
ans += flow * w;
e[i].c -= flow;
e[i ^ 1].c += flow;
sum += flow;
mf -= flow;
}
}
vis[u] = 0;
return sum;
}
inline pair<ll, ll> dinic(){
ll sum = 0, ans = 0;
while(spfa()){
memcpy(now, head, sizeof(int) * (node + 1));
sum += dfs(s, INF, ans);
}
return {sum, ans};
}
}
char c;
int n, m, s, t;
int dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0};
inline char get(){
char c = getchar();
while(c != 'L' && c != 'R' && c != 'U' && c != 'D')
c = getchar();
return c;
}
inline int id(int i, int j, int k){
return (i - 1) * m + j + k * n * m;
}
int main(){
n = read(), m = read();
MCMF::s = s = 0, MCMF::t = MCMF::node = t = 2 * n * m + 1;
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= m; ++j){
c = get();
int op = (c == 'L' || c == 'R') ? (c == 'L' ? 1 : 0) : (c == 'U' ? 3 : 2);
for(int k = 0; k < 4; ++k){
int di = i + dx[k], dj = j + dy[k];
if(di > n) di = 1;
if(!di) di = n;
if(dj > m) dj = 1;
if(!dj) dj = m;
MCMF::Add(id(i, j, 0), id(di, dj, 1), 1, k != op);
}
MCMF::Add(s, id(i, j, 0), 1, 0);
MCMF::Add(id(i, j, 1), t, 1, 0);
}
}
write(MCMF::dinic().se);
return 0;
}