0
点赞
收藏
分享

微信扫一扫

bzoj3171&luogu3965 [TJOI2013]循环格

hoohack 2022-08-08 阅读 22


(​​http://www.elijahqi.win/2017/12/11/bzoj3171luogu3965-tjoi2013%E5%BE%AA%E7%8E%AF%E6%A0%BC/%20%E2%80%8E​​​)
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

建图方法 好神 啊 自己yy一个错误做法 可惜最后还是看了题解的

针对原题的这个要求可以转化成 每个点的入度和出度恰好为1 保证这一点即可

那么我们把每个点拆成入度点和出度点 然后互相连边跑费用流即可

源点向每个点的入度连边 每个点出度向汇点连边 然后向四周连边 如果原来就是指向这个方向 那么显然 花费就是0否则我需要花费1才可以 为了满足原图的要求 我肯定是最大流就可以满足 这时候再看下费用即可

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define inf 0x3f3f3f3f
#define N 500
using namespace std;
char s[N][N];
int dx[]={0,1,0,-1},dy[]={1,0,-1,0},num=1,r,c,T,nn;
inline int calc(int x,int y,int op){
if (op==1) return (x-1)*c+y;else return (x-1)*c+y+nn;
}
int h[N],pre[N],path[N],flag[N],f[N];
struct node{
int y,z,next,c;
}data[N<<4];
inline void insert1(int x,int y,int z,int c){
data[++num].y=y;data[num].z=z;data[num].next=h[x];h[x]=num;data[num].c=c;
data[++num].y=x;data[num].z=0;data[num].next=h[y];h[y]=num;data[num].c=-c;
}
inline bool spfa(){
queue<int>q;memset(flag,0,sizeof(flag));memset(f,0x3f,sizeof(f));flag[0]=1;f[0]=0;memset(pre,-1,sizeof(pre));q.push(0);
while(!q.empty()){
int x=q.front();q.pop();flag[x]=0;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y,z=data[i].z,c=data[i].c;
if (f[x]+c<f[y]&&z){
f[y]=f[x]+c;pre[y]=x;path[y]=i;
if (!flag[y]) flag[y]=1,q.push(y);
}
}
}if (pre[T]==-1) return 0;else return 1;
}
int main(){
freopen("bzoj3171.in","r",stdin);
scanf("%d%d",&r,&c);T=r*c*2+1;nn=r*c;
for (int i=1;i<=r;++i) scanf("%s",s[i]+1);
for (int i=1;i<=r;++i){
for (int j=1;j<=c;++j){
int tmp;if (s[i][j]=='R') tmp=0;insert1(0,calc(i,j,1),1,0);insert1(calc(i,j,2),T,1,0);
if (s[i][j]=='D') tmp=1;if(s[i][j]=='L') tmp=2;if (s[i][j]=='U') tmp=3;
for (int k=0;k<4;++k){
int x1=i+dx[k],y1=j+dy[k];if (x1==0) x1=r;if (x1==r+1) x1=1;if (y1==0) y1=c;if (y1==c+1) y1=1;
if(tmp==k){insert1(calc(i,j,1),calc(x1,y1,2),1,0);continue;}
insert1(calc(i,j,1),calc(x1,y1,2),1,1);
}
}
}int ans=0;
while(spfa()){
int now=T,minn=inf;
while(now) minn=min(minn,data[path[now]].z),now=pre[now];now=T;
while(now){ans+=minn*data[path[now]].c;data[path[now]].z-=minn;data[path[now]^1].z+=minn;now=pre[now];}
}printf("%d",ans);
return 0;
}


举报

相关推荐

0 条评论