题意

一个循环格就是一个矩阵,其中所有元素为箭头,指向相邻四个格子。每个元素有一个坐标(行,列),其中左上角元素坐标为(0,0)。给定一个起始位置(r,c),你可以沿着箭头防线在格子间行走。即如果(r,c)是一个左箭头,那么走到(r,c-1);如果是右箭头那么走到(r,c+1);如果是上箭头那么走到(r-1,c);如果是下箭头那么走到(r+1,c);每一行和每一列都是循环的,即如果走出边界,你会出现在另一侧。

一个完美的循环格是这样定义的:对于任意一个起始位置,你都可以i沿着箭头最终回到起始位置。如果一个循环格不满足完美,你可以随意修改任意一个元素的箭头直到完美。给定一个循环格,你需要计算最少需要修改多少个元素使其完美。

思路

显然满足题中条件的图需要满足每个点的出度和入度都为1。

考虑费用流,把每个点\((i,j)\)拆成两个点\((i_1,j_1)\)和\((i_2,j_2)\)。

因为一个点只能有一个出度,所以\(S-(i_1,j_1)\)的容量应该为1,

同理\((i_2,j_2)-T\)的容量也应该为1,\((i_1,j_1)\)和\((i_2,j_2)\)之间互相连边,

原图中的边对应与新图的边费用应该为0,其余三个方向的边费用设为1.

那么跑一遍minCostmaxFlow即可得出答案。

代码

# include<bits/stdc++.h>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-8
# define MOD 100000007
# define INF 1e16
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(register int i=a; i<=n; ++i)
# define FDR(i,a,n) for(register int i=a; i>=n; --i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
inline char nc(){
static char buf[1000000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int Scan(){
char ch=nc();int sum=0, f=1;
if (ch=='-') f=-1, ch=nc();
while(!(ch>='0'&&ch<='9'))ch=nc();
while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
return sum*f;
}
const int N=250;
//Code begin.... int n, m, s, t;
char G[20][20];
struct Edge{
int to, next, cap, flow, cost;
}edge[N*20];
int head[N<<1], tol, pre[N<<1], dis[N<<1], nn;
bool vis[N<<1];
int ps[4][2]={1,0,-1,0,0,1,0,-1}; int ID(int x, int y){return x*m+y;}
void init(int n){nn=n; tol=0; mem(head,-1);}
void add_edge(int u, int v, int cap, int cost){
edge[tol]=Edge{v,head[u],cap,0,cost}; head[u]=tol++;
edge[tol]=Edge{u,head[v],0,0,-cost}; head[v]=tol++;
}
bool spfa(int s, int t){
queue<int>q;
FOR(i,0,nn-1) dis[i]=INF, vis[i]=false, pre[i]=-1;
dis[s]=0; vis[s]=true; q.push(s);
while (!q.empty()) {
int u=q.front(); q.pop();
vis[u]=false;
for (int i=head[u]; i!=-1; i=edge[i].next) {
int v=edge[i].to;
if (edge[i].cap>edge[i].flow && dis[v]>dis[u]+edge[i].cost) {
dis[v]=dis[u]+edge[i].cost;
pre[v]=i;
if (!vis[v]) vis[v]=true, q.push(v);
}
}
}
if (pre[t]==-1) return false;
else return true;
}
int minCostmaxFlow(int s, int t, int &cost){
int flow=0;
cost=0;
while (spfa(s,t)) {
int Min=INF;
for (int i=pre[t]; i!=-1; i=pre[edge[i^1].to]) {
if (Min>edge[i].cap-edge[i].flow) Min=edge[i].cap-edge[i].flow;
}
for (int i=pre[t]; i!=-1; i=pre[edge[i^1].to]) {
edge[i].flow+=Min; edge[i^1].flow-=Min;
cost+=edge[i].cost*Min;
}
flow+=Min;
}
return flow;
}
int main ()
{
scanf("%d%d",&n,&m);
s=2*n*m; t=2*n*m+1;
init(t+1);
FOR(i,0,n-1) scanf("%s",G[i]);
FOR(i,0,n-1) FOR(j,0,m-1) {
FOR(k,0,3) {
int dx=(i+ps[k][0]+n)%n, dy=(j+ps[k][1]+m)%m;
if ((k==0&&G[i][j]=='D')||(k==1&&G[i][j]=='U')||(k==2&&G[i][j]=='R')||(k==3&&G[i][j]=='L')) add_edge(ID(i,j),ID(dx,dy)+n*m,1,0);
else add_edge(ID(i,j),ID(dx,dy)+n*m,1,1);
}
add_edge(s,ID(i,j),1,0), add_edge(ID(i,j)+n*m,t,1,0);
}
int cost;
minCostmaxFlow(s,t,cost);
printf("%d\n",cost);
return 0;
}

BZOJ 3171 循环格(费用流)的更多相关文章

  1. Bzoj 3171: [Tjoi2013]循环格 费用流

    3171: [Tjoi2013]循环格 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 741  Solved: 463[Submit][Status][ ...

  2. BZOJ 3171 循环格 最小费用流

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=3171 题目大意: 一个循环格就是一个矩阵,其中所有元素为箭头,指向相邻四个格子.每个元 ...

  3. [TJOI2013]循环格 费用流 BZOJ3171

    题目背景 一个循环格就是一个矩阵,其中所有元素为箭头,指向相邻四个格子.每个元素有一个坐标(行,列),其中左上角元素坐标为(0,0).给定一个起始位(r,c),你可以沿着箭头方向在格子间行走.即:如果 ...

  4. BZOJ 3171 循环格(费用流)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3171 题意: 思路:若能构成循环,则每个格子的入度出度 均为1.因此将每个点拆成两个点x ...

  5. [bzoj 1449] 球队收益(费用流)

    [bzoj 1449] 球队收益(费用流) Description Input Output 一个整数表示联盟里所有球队收益之和的最小值. Sample Input 3 3 1 0 2 1 1 1 1 ...

  6. BZOJ.2597.[WC2007]剪刀石头布(费用流zkw)

    BZOJ 洛谷 \(Description\) 给定一张部分边方向已确定的竞赛图.你需要给剩下的边确定方向,使得图中的三元环数量最多. \(n\leq100\). \(Solution\) 这种选择之 ...

  7. bzoj 1070: [SCOI2007]修车 费用流

    1070: [SCOI2007]修车 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 2785  Solved: 1110[Submit][Status] ...

  8. BZOJ 1070 修车 【费用流】

    Description 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同 的车进行维修所用的时间是不同的.现在需要安排这M位技术人员所维修的车及顺序, ...

  9. BZOJ 1930 吃豆豆(费用流)

    首先这题的两条线不相交的限制可以去掉,因为如果相交的话把点换一换是不影响最终结果的. 剩下的费用流建图是显然的,把点拆为两个,建立超级源点s和源点ss汇点t,连边(s,ss,2,0). 对于每个点,连 ...

随机推荐

  1. 向jupyter notebook加入Anaconda3中已添加的虚拟环境kernel

    # jupyter notebook添加Anaconda虚拟环境的kernel #  开启虚拟环境 (base) C:\Users\jiangshan>activate tensorflow # ...

  2. css样式匹配苹果个型号手机

    /*适配苹果X*/ @media only screen and (device-width: 375px) and (device-height: 812px) and (-webkit-devic ...

  3. nodejs 模板引擎ejs的使用

    1.test.ejs文件 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...

  4. day07--字符编码、文件处理

    今日内容: 字符编码 文件处理 字符编码: 把字符编码成二进制 各个国家拥有各自的字符编码,这样会导致交流产生问题.所以后面推出了内存使用unicode,硬盘使用UTF-8这个模式 unicode有两 ...

  5. LIN、CAN、FlexRay、MOST,三分钟搞明白四大汽车总线

    LIN.CAN.FlexRay.MOST,三分钟搞明白四大汽车总线 2016-09-21 13:09 汽车中的电子部件越来越多,光是ECU就有几十个,这么多的电子单元都要进行信息交互.传统的点对点通信 ...

  6. 大数据入门第二十二天——spark(二)RDD算子(1)

    一.RDD概述 1.什么是RDD RDD(Resilient Distributed Dataset)叫做分布式数据集,是Spark中最基本的数据抽象,它代表一个不可变.可分区.里面的元素可并行计算的 ...

  7. # 2017-2018-2 20155319『网络对抗技术』Exp5:MSF基础应用

    2017-2018-2 20155319『网络对抗技术』Exp5:MSF基础应用 基础问题回答 用自己的话解释什么是exploit,payload,encode exploit:使用者利用漏洞进行攻击 ...

  8. 事务特性,事务的隔离级别,并发事务可能出现的问题,spring事务 数据库锁

    1.0 事务特性(ACID) Atomicity:原子性,一个事务不可以被拆分 Consistency:一致性,在事务执行前数据库的数据处于正确的状态,而事务执行完成后数据库的数据还是处于正确的状态, ...

  9. python程序出现No module named '_socket' 解决方法

    首先看一下这个错误,错误显示没有这个_socket这个模块 看一个简单的程序理解这个错误是怎么出现的 这个程序就是像浏览器发起请求发开一个链接然后关闭,一直循环,运行之后产生这个错误,产生这个错误的原 ...

  10. OpenMPI源码剖析:网络通信原理(二) 如何选择网络协议?

    因为比较常用的是 TCP 协议,所以在 opal/mca/btl/tcp/btl_tcp.h 头文件中找到对应的 struct mca_btl_tcp_component_t { mca_btl_ba ...