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
分析:
很明显,图中只能有若干个环
这就像一个欧拉回路一样,
每个点的出度一定等于入度
然而每个点的出度都是一,那也就是说入度一定是一
这样就变成了怎么改变方向,使每个格子的出度和入度都等于一
这就让我想起了有一道混合图的网络流题
那道题就是让我们给每一条无向边定向,
使得图成为一个欧拉路
每改变一个格子的方向就会使两个格子的入度更改
我一开始想的很简单:
把每个点拆成两个点
称作1部,2部
如果x—>y
我们就连接x1—>y2
跑一个最大匹配,
最后答案是点数-最大匹配
结果发现连样例都过不了
实际上这是一道最小费用最大流
还是拆点,每个点向相邻的格子连边,
如果是箭头所指的方向,那么费用是0
否则费用为1
跑一遍费用流就可以了
tip
我一开始的理解是只能在格子内奔跑,
如果跑了出去是不合法的,
后来才明白,题目的意思是循环奔跑,跑出去了之后再从头开始
这里写代码片
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int INF=0x33333333;
const int N=40001;
struct node{
int x,y,v,c,nxt;
};
node way[N<<2];
int st[N],pre[N],tot=-1,dis[N],q[N],tou,wei,n,m,deep[N],cur[N],s,t;
bool p[N];
int get(int x,int y){return (x-1)*m+y;}
void add(int u,int w,int v,int cc)
{
tot++;
way[tot].x=u;way[tot].y=w;way[tot].c=cc;way[tot].v=v;way[tot].nxt=st[u];st[u]=tot;
tot++;
way[tot].x=w;way[tot].y=u;way[tot].c=-cc;way[tot].v=0;way[tot].nxt=st[w];st[w]=tot;
}
int spfa(int s,int t)
{
memset(dis,0x33,sizeof(dis));
memset(pre,-1,sizeof(pre));
memset(p,1,sizeof(p));
tou=wei=0;
q[++wei]=s;
p[s]=0; dis[s]=0;
do
{
int r=q[++tou];
for (int i=st[r];i!=-1;i=way[i].nxt)
if (way[i].v&&dis[r]+way[i].c<dis[way[i].y])
{
dis[way[i].y]=dis[r]+way[i].c;
pre[way[i].y]=i;
if (p[way[i].y])
{
p[way[i].y]=0;
q[++wei]=way[i].y;
}
}
p[r]=1;
}
while (tou<wei);
return dis[t]!=INF;
}
void doit()
{
int ans=0;
while (spfa(s,t))
{
int sum=INF;
for (int i=t;i!=s;i=way[pre[i]].x)
sum=min(sum,way[pre[i]].v);
ans+=sum*dis[t];
for (int i=t;i!=s;i=way[pre[i]].x)
way[pre[i]].v-=sum,
way[pre[i]^1].v+=sum;
}
printf("%d",ans);
}
int main()
{
memset(st,-1,sizeof(st));
scanf("%d%d",&n,&m);
s=0; t=n*m*2+1;
char ch[20];
for (int i=1;i<=n;i++)
{
scanf("%s",&ch);
for (int j=1;j<=m;j++)
{
int now=get(i,j);
add(s,now,1,0);
add(now+n*m,t,1,0);
int xx,yy;
if (ch[j-1]=='U'){
xx=(i-1==0 ? n:i-1); add(now,get(xx,j)+n*m,1,0);
yy=(j-1==0 ? m:j-1); add(now,get(i,yy)+n*m,1,1);
xx=(i+1>n ? 1:i+1); add(now,get(xx,j)+n*m,1,1);
yy=(j+1>m ? 1:j+1); add(now,get(i,yy)+n*m,1,1);
}
else if (ch[j-1]=='D'){
xx=(i-1==0 ? n:i-1); add(now,get(xx,j)+n*m,1,1);
yy=(j-1==0 ? m:j-1); add(now,get(i,yy)+n*m,1,1);
xx=(i+1>n ? 1:i+1); add(now,get(xx,j)+n*m,1,0);
yy=(j+1>m ? 1:j+1); add(now,get(i,yy)+n*m,1,1);
}
else if (ch[j-1]=='R'){
xx=(i-1==0 ? n:i-1); add(now,get(xx,j)+n*m,1,1);
yy=(j-1==0 ? m:j-1); add(now,get(i,yy)+n*m,1,1);
xx=(i+1>n ? 1:i+1); add(now,get(xx,j)+n*m,1,1);
yy=(j+1>m ? 1:j+1); add(now,get(i,yy)+n*m,1,0);
}
else
{
xx=(i-1==0 ? n:i-1); add(now,get(xx,j)+n*m,1,1);
yy=(j-1==0 ? m:j-1); add(now,get(i,yy)+n*m,1,0);
xx=(i+1>n ? 1:i+1); add(now,get(xx,j)+n*m,1,1);
yy=(j+1>m ? 1:j+1); add(now,get(i,yy)+n*m,1,1);
}
}
}
doit();
return 0;
}