博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ3171: [Tjoi2013]循环格
阅读量:5312 次
发布时间:2019-06-14

本文共 3295 字,大约阅读时间需要 10 分钟。

3171: [Tjoi2013]循环格

Time Limit: 1 Sec Memory Limit: 128 MB

Submit: 1155 Solved: 730
[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

Sample Output

2

HINT

1<=R,L<=15

题解

结论,n个点的有向图,只能连n条边,每个点都在回路内,当且仅当所有点出度入度都为1。

先证充分, n条边,能够提供n个入度,n个出度,如果一个点入度大于1, 那么存在点的入度为0,走不出去,不能成回路。所以一个点入度必须为1。出度同理。
再证必要,所有点出度入度都为1,所以只有一条路径可走。从一个点开始走,由于点数有限,若回不来,一定在某个地方走成了回路,那么入口处的点就会有两个入度,矛盾。

一个点拆为两个,左边为出度点,右边为入度点。

每个点改方向费用为1,不改费用为0.
问题转化为二分图最小权完美匹配。

#include 
#include
#include
#include
#include
#include
#include
inline int max(int a, int b){return a > b ? a : b;}inline int min(int a, int b){return a < b ? a : b;}inline int abs(int x){return x < 0 ? -x : x;}inline void swap(int &x, int &y){int tmp = x;x = y;y = tmp;}inline void read(int &x){ x = 0;char ch = getchar(), c = ch; while(ch < '0' || ch > '9') c = ch, ch = getchar(); while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar(); if(c == '-') x = -x;}const int INF = 0x3f3f3f3f;const int dx[4] = {0, 0, 1, -1};const int dy[4] = {1, -1, 0, 0};struct Edge{ int u,v,w,c,nxt; Edge(int _u, int _v, int _w, int _c, int _nxt){u = _u;v = _v;w = _w;c = _c;nxt = _nxt;} Edge(){}}edge[1000010];int head[1000010], cnt = 1, S, T, q[1000010], he, ta, d[1000010], vis[1000010], from[1000010], ans;inline void insert(int a, int b, int c, int d){ edge[++ cnt] = Edge(a, b, c, d, head[a]), head[a] = cnt; edge[++ cnt] = Edge(b, a, 0, -d, head[b]), head[b] = cnt;}bool spfa(){ memset(d, 0x3f, sizeof(d)), d[S] = 0, he = 0, ta = 1, q[0] = S, vis[S] = 1; while(he < ta) { int now = q[he ++];if(he > 1000000) he = 0; for(int pos = head[now];pos;pos = edge[pos].nxt) { int v = edge[pos].v; if(edge[pos].w && d[v] > d[now] + edge[pos].c) { d[v] = d[now] + edge[pos].c, from[v] = pos; if(!vis[v]) { q[ta ++] = v; if(ta > 1000000) ta = 0; } } } vis[now] = 0; } return d[T] != INF;}void flow(){ int mi = INF; for(int i = from[T];i;i = from[edge[i].u]) mi = min(mi, edge[i].w); for(int i = from[T];i;i = from[edge[i].u]) edge[i].w -= mi, edge[i ^ 1].w += mi, ans += edge[i].c * mi;}void mcf(){ while(spfa()) flow();}int n, m, num[101][101][2], tot; char g[101][101];int main(){ read(n), read(m); for(int i = 0;i < n;++ i) { scanf("%s", g[i]); for(int j =0;j < m;++ j) num[i][j][0] = ++ tot, num[i][j][1] = ++ tot; } S = tot + 1, T = S + 1; //R L D U for(int i = 0;i < n;++ i) for(int j = 0;j < m;++ j) { insert(S, num[i][j][0], 1, 0), insert(num[i][j][1], T, 1, 0); for(int k = 0;k < 4;++ k) { int val = 1, xx = (i + dx[k] + n) % n, yy = (j + dy[k] + m) % m; if(k == 0 && g[i][j] == 'R') val = 0; if(k == 1 && g[i][j] == 'L') val = 0; if(k == 2 && g[i][j] == 'D') val = 0; if(k == 3 && g[i][j] == 'U') val = 0; insert(num[i][j][0], num[xx][yy][1], 1, val); } } mcf(); printf("%d", ans); return 0;}

转载于:https://www.cnblogs.com/huibixiaoxing/p/8521176.html

你可能感兴趣的文章
_stdcall 函数 debug/release汇编代码区别
查看>>
快速构建Windows 8风格应用7-页面视图概览
查看>>
The Definitive Guide To Django 2 学习笔记(五) 第四章 模板 (一)基本模板系统
查看>>
eclipse中logcat偶尔不显示log的问题解决办法
查看>>
mac环境下安装配置mysql
查看>>
Radar Installation 贪心
查看>>
js浮点数的加减乘除
查看>>
svg绘制一个简单地饼图
查看>>
从零开始学习html(十四)单位和值
查看>>
atom编辑器安装说明
查看>>
团队组员得分分配工作(改动)——PM(李忠)
查看>>
我的开源项目
查看>>
Display BLOBs and CLOBs (DB2可视化工具AQT )
查看>>
adb的使用介绍(转载)
查看>>
linux下打开windows txt文件中文乱码问题 (转载)
查看>>
JVM菜鸟进阶高手之路六(JVM每隔一小时执行一次Full GC)
查看>>
Spring Boot中使用Swagger2构建强大的RESTful API文档
查看>>
怎么看吉他简谱
查看>>
java_流程控制
查看>>
解决Azure中COULD NOT LOAD FILE OR ASSEMBLY问题
查看>>