【bzoj3171】[Tjoi2013]循环格
题目描述:
一个循环格就是一个矩阵,其中所有元素为箭头,指向相邻四个格子。每个元素有一个坐标(行,列),其中左上角元素坐标为(0,0)。给定一个起始位置(r,c)
,你可以沿着箭头防线在格子间行走。即如果(r,c)是一个左箭头,那么走到(r,c-1);如果是右箭头那么走到(r,c+1);如果是上箭头那么走到(r-1,c);如果是下箭头那么走到(r+1,c);每一行和每一列都是循环的,即如果走出边界,你会出现在另一侧。
一个完美的循环格是这样定义的:对于任意一个起始位置,你都可以i沿着箭头最终回到起始位置。如果一个循环格不满足完美,你可以随意修改任意一个元素的箭头直到完美。给定一个循环格,你需要计算最少需要修改多少个元素使其完美。
输入:
第一行两个整数R,C。表示行和列,接下来R行,每行C个字符LRUD,表示左右上下。
输出:
一个整数,表示最少需要修改多少个元素使得给定的循环格完美
样例输入:
3 4
RRRD
URLL
LRRR
样例输出:
2
题解:
这题有两种构图方法。首先,两种方法根据出入度都为1来构图。
第一种:
(1)将所有的点拆成两个点,将一个点连向源点S,另一个点连向汇点T,连的边都是容量为1,费用为0的。代表了每个点的出入度都是1 。
(2)一个点向四周的另一类点连出一条容量为1费用为0或1(如果无需修改就是0,否则需要修改就是1)的边。
(3)跑最小费用最大流
第二种:
(1)拆点同上,但连的边的容量为该点原本的入(出)度。
(2)对于每个方格(i, j),我们假设原本连的点为(x,y),那么把这个连向的点的第二类点向其他三个没连的点的第一类点连边,容量为1,费用为1。每个第一类点和第二类点之间都连一条容量为1,费用为0的边。
(3)同第一种
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#ifdef WIN32
#define LL "%I64d"
#else
#define LL "%lld"
#endif
#ifdef CT
#define debug(...) printf(__VA_ARGS__)
#define setfile()
#else
#define debug(...)
#define filename ""
#define setfile() freopen(filename".in", "r", stdin); freopen(filename".out", "w", stdout);
#endif
#define R register
#define getc() (S == T && (T = (S = B) + fread(B, 1, 1 << 15, stdin), S == T) ? EOF : *S++)
#define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b))
#define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b))
#define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0)
#define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0)
char B[1 << 15], *S = B, *T = B;
inline int FastIn()
{
R char ch; R int cnt = 0; R bool minus = 0;
while (ch = getc(), (ch < '0' || ch > '9') && ch != '-') ;
ch == '-' ? minus = 1 : cnt = ch - '0';
while (ch = getc(), ch >= '0' && ch <= '9') cnt = cnt * 10 + ch - '0';
return minus ? -cnt : cnt;
}
#define maxn 20
#define maxcnt 1010
#define maxm 100010
struct Edge
{
int from, to, w, c;
Edge *next, *rev;
}*last[maxcnt], *prev[maxcnt], e[maxm], *ecnt = e;
int opt[maxn][maxn], id[maxn][maxn], s, t, ans;
int dis[maxcnt];
bool vis[maxcnt];
const int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};
#define cmod(_a, _b) ((_a) % (_b) == 0 ? (_b) : (_a) % (_b))
inline void link(R int _a, R int _b, R int _w, R int _c)
{
*++ecnt = (Edge) {_a, _b, _w, _c, last[_a], ecnt + 1}; last[_a] = ecnt;
*++ecnt = (Edge) {_b, _a, 0, -_c, last[_b], ecnt - 1}; last[_b] = ecnt;
}
#define INF 23333333
std::queue <int> q;
inline bool spfa()
{
for (R int i = 0; i <= t; ++i) dis[i] = INF;
dis[s] = 0; vis[s] = 1; q.push(s);
while (!q.empty())
{
R int now = q.front(); q.pop();
for (R Edge *iter = last[now]; iter; iter = iter -> next)
{
if (iter -> w && iter -> c + dis[now] < dis[iter -> to])
{
dis[iter -> to] = iter -> c + dis[now];
prev[iter -> to] = iter;
if (!vis[iter -> to])
{
vis[iter -> to] = 1;
q.push(iter -> to);
}
}
}
vis[now] = 0;
}
return dis[t] != INF;
}
inline void mcmf()
{
R int x = INF;
for (R Edge *iter = prev[t]; iter; iter = prev[iter -> from])
cmin(x, iter -> w);
for (R Edge *iter = prev[t]; iter; iter = prev[iter -> from])
{
ans += x * iter -> c;
iter -> w -= x;
iter -> rev -> w += x;
}
}
int main()
{
R int n = FastIn(), m = FastIn(), cnt = 0;
for (R int i = 1; i <= n; ++i)
for (R int j = 1; j <= m; ++j)
{
id[i][j] = ++cnt;
R char ch;
while (ch = getc(), ch < 'A' || ch > 'Z');
if (ch == 'U') opt[i][j] = 0;
if (ch == 'D') opt[i][j] = 1;
if (ch == 'L') opt[i][j] = 2;
if (ch == 'R') opt[i][j] = 3;
}
s = 0; t = cnt << 1 | 1;
for (R int i = 1; i <= n; ++i)
for (R int j = 1; j <= m; ++j)
{
link(s, id[i][j], 1, 0);
link(id[i][j] + cnt, t, 1, 0);
for (R int k = 0; k < 4; ++k)
{
R int nx = i + dx[k], ny = j + dy[k];
link(id[i][j], id[cmod(nx, n)][cmod(ny, m)] + cnt, 1, k == opt[i][j] ? 0 : 1);
}
}
while (spfa()) mcmf();
printf("%d\n",ans );
return 0;
}
【bzoj3171】[Tjoi2013]循环格的更多相关文章
- BZOJ3171 Tjoi2013 循环格
传送门 Description 一个循环格就是一个矩阵,其中所有元素为箭头,指向相邻四个格子.每个元素有一个坐标(行,列),其中左上角元素坐标为(0,0).给定一个起始位置(r,c) ,你可以沿着箭头 ...
- bzoj3171: [Tjoi2013]循环格(费用流)
传送门 其实这题的建图并不难(虽然我并没有想出来) 首先,每一个点的入度和出度必须为$1$ 那么我们考虑拆点 每个点的出度点向它能到达的点的入度点连边,容量$1$,如果方向为原来的方向则费用$0$否则 ...
- Bzoj 3171: [Tjoi2013]循环格 费用流
3171: [Tjoi2013]循环格 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 741 Solved: 463[Submit][Status][ ...
- [Tjoi2013]循环格
[Tjoi2013]循环格 2014年3月18日1,7500 Description Input 第一行两个整数R,C.表示行和列,接下来R行,每行C个字符LRUD,表示左右上下. Output 一个 ...
- 洛谷 P3965 [TJOI2013]循环格 解题报告
P3965 [TJOI2013]循环格 题目背景 一个循环格就是一个矩阵,其中所有元素为箭头,指向相邻四个格子. 每个元素有一个坐标(行,列),其中左上角元素坐标为\((0,0)\).给定一个起始位\ ...
- BZOJ_3171_[Tjoi2013]循环格_最小费用最大流
BZOJ_3171_[Tjoi2013]循环格_最小费用最大流 Description 一个循环格就是一个矩阵,其中所有元素为箭头,指向相邻四个格子.每个元素有一个坐标(行,列),其中左上角元素坐标为 ...
- [TJOI2013]循环格 费用流 BZOJ3171
题目背景 一个循环格就是一个矩阵,其中所有元素为箭头,指向相邻四个格子.每个元素有一个坐标(行,列),其中左上角元素坐标为(0,0).给定一个起始位(r,c),你可以沿着箭头方向在格子间行走.即:如果 ...
- 【BZOJ3171】[TJOI2013] 循环格(网络流)
点此看题面 大致题意: 给你一个循环格,每个格子有一个方向.问你至少修改多少格子,才能使从每个格子出发都能回到原格子. 建图 这是道网络流题目,主要就是考虑如何建图. 我们可以把每个点拆成两个点,一个 ...
- bzoj 3171: [Tjoi2013]循环格
#include<cstdio> #include<iostream> #include<cstring> #define M 10000 #define inf ...
随机推荐
- 20191127 Spring Boot官方文档学习(4.25)
4.25. Testing Spring Boot提供了许多实用程序和注解,可以在测试应用程序时提供帮助.测试支持由两个模块提供:spring-boot-test包含核心项,spring-boot-t ...
- linux应用程序启动时加载库错误问题
ldd text查看依赖库 ln -s /lib64/libpcre.so.0 /usr/local/lib/libpcre.so做软连接
- JAVA基础面向对象分析
面向对象内存的分析: 一:内存的分类 1:栈(tack) 2:堆(heop) 3: 静态区 4:代码区 二:引用数据类型内存特点 三:引用数据类型传值的特点 四:引用数据类型在作为参数时的特点 面向对 ...
- Redis进阶:Redis的主从复制机制
Redis进阶:Redis的主从复制机制 主从复制机制介绍 单机版的Redis存在性能瓶颈,Redis通过提高主从复制实现读写分离,提高了了Redis的可用性,另一方便也能实现数据在多个Redis直接 ...
- maven指定本地jar包
来自 https://blog.csdn.net/zhengxiangwen/article/details/50734565 一.怎么添加jar到本地仓库呢?步骤:1.cmd命令进入该jar包所在路 ...
- XLS导出的服务器端配置方式
IIS支持excel导出: 1.开始—运行,然后键入DCOMCNFG; 2.组件服务—计算机—我的电脑—DCOM配置,这时弹出一个问注册的窗口,确定注册. 这时如果一切恢复正常了,不用往下操作了. 关 ...
- 从汇编到C
一. 设置栈 1.1. C语言运行时需要和栈的意义 1.1.1. “C语言运行时(runtime)”需要一定的条件,这些条件由汇编来提供.C语言运行时主要是需要栈 1.1.2. C语言与栈的关系 a. ...
- 6-2 如何读写json数据
通过查看help(json.dump)和help(json.dumps)帮助信息,dump是将转换格式到文件对象,而dumps转换格式到字符串. 一.Json.dumps() Json.dumps() ...
- oracle数据库中的存储函数
oracle中的存储函数,和系统内的函数类似,可以像调用系统函数一样调用存储函数.它与存储过程的唯一区别就是存储过程没有return返回值,存储函数可以与存储过程互换,存储函数可以在存储过程中调用. ...
- rabitMQ-centos7安装
1.安装rabitMq之前需要安装Erlang cd /usr/local/ wget http://erlang.org/download/otp_src_18.3.tar.gz tar -zxvf ...