bzoj3171 [Tjoi2013]循环格
3171: [Tjoi2013]循环格
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 1169 Solved: 736
[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
分析:利用容量来满足限制的经典应用.
首先考虑循环格的特征:每个格子的出度为1,入度为1. 如果把每个点拆成两个点:入点和出点. 对于出点,由源点向其连一条容量为1的边,对于入点,由其向汇点连一条容量为1的边. 这样满流的时候,所有点的入度和出度就都是1了.
接下来考虑点与点之间的连边. 考虑每一对相邻的点.对于原图中存在的边,从出点连向入点,费用为0,如果如果边不存在(由存在的边旋转得到),则费用为1.
有了S和T流量的限制,就能满足要求,并且使得费用最小了.
注意:数组要开大! 计算边数一定不要忘了计算反向边! 一个好的方法是看每一个循环中出现了多少条连边语句,总和乘2就是边数了.
#include <cstdio> #include <queue> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 1010,inf = 0x7fffffff,dx[] = {0,0,1,-1},dy[] = {1,-1,0,0}; int n,m,S,T,ans,head[maxn],to[maxn * 20],nextt[maxn * 20],w[maxn * 20],cost[maxn * 20],tot = 2; char s[maxn][maxn]; int vis[maxn],vis2[maxn],d[maxn]; void add(int x,int y,int z,int p) { cost[tot] = p; w[tot] = z; to[tot] = y; nextt[tot] = head[x]; head[x] = tot++; cost[tot] = -p; w[tot] = 0; to[tot] = x; nextt[tot] = head[y]; head[y] = tot++; } bool spfa() { for (int i = 1; i <= T; i++) d[i] = inf; memset(vis,0,sizeof(vis)); memset(vis2,0,sizeof(vis2)); d[S] = 0; vis[S] = 1; queue <int> q; q.push(S); while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for (int i = head[u];i;i = nextt[i]) { int v = to[i]; if (w[i] && d[v] > d[u] + cost[i]) { d[v] = d[u] + cost[i]; if (!vis[v]) { vis[v] = 1; q.push(v); } } } } return d[T] < inf; } int dfs(int u,int f) { if (u == T) { ans += d[u] * f; return f; } int res = 0; vis2[u] = 1; for (int i = head[u];i;i = nextt[i]) { int v = to[i]; if (!vis2[v] && w[i] && d[v] == d[u] + cost[i]) { int temp = dfs(v,min(f - res,w[i])); w[i] -= temp; w[i ^ 1] += temp; res += temp; if (res == f) return res; } } return res; } void dinic() { while (spfa()) dfs(S,inf); } int calc(int x,int y) { return (x - 1) * m + y; } int main() { scanf("%d%d",&n,&m); S = n * m * 2 + 1; T = S + 1; for (int i = 1; i <= n; i++) scanf("%s",s[i] + 1); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { int ti = i,tj = j; if (s[i][j] == 'R') tj++; if (s[i][j] == 'L') tj--; if (s[i][j] == 'U') ti--; if (s[i][j] == 'D') ti++; if (tj == m + 1) tj = 1; if (tj == 0) tj = m; if (ti == n + 1) ti = 1; if (ti == 0) ti = n; int temp = calc(i,j),temp2 = calc(ti,tj); add(S,temp + n * m,1,0); add(temp,T,1,0); add(temp + n * m,temp2,1,0); for (int k = 0; k < 4; k++) { int di = i + dx[k],dj = j + dy[k]; if (dj == m + 1) dj = 1; if (dj == 0) dj = m; if (di == n + 1) di = 1; if (di == 0) di = n; if (di == ti && dj == tj) continue; int temp3 = calc(di,dj); add(temp + n * m,temp3,1,1); } } dinic(); printf("%d\n",ans); return 0; }