BZOJ 3171: [Tjoi2013]循环格( 费用流 )
每个点都在某个环中, 出度都为1, 只要让入度也全为1就可以满足题意了. 然后就是裸的最小费用最大流了.
----------------------------------------------------------------------------
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<deque>
#include<bitset>
using namespace std;
#define X(x, y) (((x) * C + y) << 1)
#define Y(x, y) (((x) * C + y) << 1 | 1)
const int maxn = 20;
const int maxv = maxn * maxn * 2;
const int INF = 0X3F3F3F3F;
const int dx[4] = {-1, 0, 0, 1};
const int dy[4] = {0, 1, -1, 0};
const char dc[4] = {'U', 'R', 'L', 'D'};
int d[maxv], a[maxv];
int R, C, V, S, T;
char s[maxn];
bitset<maxv> inq;
deque<int> q;
struct edge {
int to, cap, cost;
edge *next, *rev;
} E[100000], *pt = E, *head[maxv], *p[maxv];
inline void Add(int u, int v, int c, int w) {
pt->to = v;
pt->cap = c;
pt->cost = w;
pt->next = head[u];
head[u] = pt++;
}
inline void AddEdge(int u, int v, int w) {
Add(u, v, 1, w);
Add(v, u, 0, -w);
head[u]->rev = head[v];
head[v]->rev = head[u];
}
void Solve() {
int ans = 0;
for( ; ; ) {
inq.reset();
memset(d, INF, sizeof(int) * V);
d[S] = 0;
a[S] = INF;
q.push_back(S);
while(!q.empty()) {
int x = q.front(); q.pop_front();
inq[x] = 0;
for(edge* e = head[x]; e; e = e->next) if(e->cap && d[e->to] > d[x] + e->cost) {
p[e->to] = e;
d[e->to] = d[x] + e->cost;
a[e->to] = min(a[x], e->cap);
if(inq[e->to] == 0) {
inq[e->to] = 1;
if(!q.empty() && d[q.front()] > d[e->to])
q.push_front(e->to);
else
q.push_back(e->to);
}
}
}
if(d[T] == INF)
break;
ans += d[T] * a[T];
for(int x = T; x != S; x = p[x]->rev->to) {
p[x]->cap -= a[T];
p[x]->rev->cap += a[T];
}
}
printf("%d\n", ans);
}
void Init() {
scanf("%d%d", &R, &C);
V = R * C * 2;
S = V++;
T = V++;
for(int i = 0; i < R; i++) {
scanf("%s", s);
for(int j = 0; j < C; j++) {
AddEdge(S, X(i, j), 0);
AddEdge(Y(i, j), T, 0);
for(int d = 0; d < 4; d++) {
int x = i + dx[d] + R, y = j + dy[d] + C;
while(x >= R) x -= R;
while(y >= C) y -= C;
AddEdge(X(i, j), Y(x, y), s[j] != dc[d]);
}
}
}
}
int main() {
Init();
Solve();
return 0;
}
----------------------------------------------------------------------------
3171: [Tjoi2013]循环格
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 672 Solved: 411
[Submit][Status][Discuss]
Description
一个循环格就是一个矩阵,其中所有元素为箭头,指向相邻四个格子。每个元素有一个坐标(行,列),其中左上角元素坐标为(0,0)。给定一个起始位置(r,c)
,你可以沿着箭头防线在格子间行走。即如果(r,c)是一个左箭头,那么走到(r,c-1);如果是右箭头那么走到(r,c+1);如果是上箭头那么走到(r-1,c);如果是下箭头那么走到(r+1,c);每一行和每一列都是循环的,即如果走出边界,你会出现在另一侧。
一个完美的循环格是这样定义的:对于任意一个起始位置,你都可以i沿着箭头最终回到起始位置。如果一个循环格不满足完美,你可以随意修改任意一个元素的箭头直到完美。给定一个循环格,你需要计算最少需要修改多少个元素使其完美。
Input
第一行两个整数R,C。表示行和列,接下来R行,每行C个字符LRUD,表示左右上下。
Output
一个整数,表示最少需要修改多少个元素使得给定的循环格完美
Sample Input
3 4
RRRD
URLL
LRRR
RRRD
URLL
LRRR
Sample Output
2
HINT
1<=R,L<=15
Source