BZOJ_3171_[Tjoi2013]循环格_最小费用最大流

BZOJ_3171_[Tjoi2013]循环格_最小费用最大流

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


一开始看错题了,以为是每个格子都要回到(0,0)。

原来是每个格子回到原来的位置。

这样可以说明每个点入度和出度都为1。

于是拆点建立二分图,相邻的连上边,流量为1费用为是否不能到达。

然后跑最小费用最大流即可。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 10050
#define M 400050
#define S (2*n*m+1)
#define T (2*n*m+2)
#define inf 1<<30
#define p(i,j) ((i-1)*m+j)
int n,m,head[N],to[M],nxt[M],val[M],flow[M],cnt=1,path[N];
int Q[N],l,r,dis[N],inq[N];
char s[18][18];
int tx[]={0,1,0,-1};
int ty[]={1,0,-1,0};
inline void add(int u,int v,int f,int c) {
    to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; flow[cnt]=f; val[cnt]=c;
    to[++cnt]=u; nxt[cnt]=head[v]; head[v]=cnt; flow[cnt]=0; val[cnt]=-c;
}
bool spfa() {
    memset(dis,0x3f,sizeof(dis));
    memset(path,0,sizeof(path));
    dis[S]=0; l=r=0; Q[r++]=S;
    int i;
    while(l!=r) {
        int x=Q[l++]; inq[x]=0; if(l==T) l=0;
        for(i=head[x];i;i=nxt[i]) {
            if(dis[to[i]]>dis[x]+val[i]&&flow[i]) {
                dis[to[i]]=dis[x]+val[i];
                path[to[i]]=i^1;
                if(!inq[to[i]]) {
                    Q[r++]=to[i]; if(r==T) r=0;
                }
            }
        }
    }
    return path[T];
}
void mcmf() {
    int ans=0;
    while(spfa()) {
        // puts("FUCK");
        int nf=1<<30;
        int i;
        for(i=T;i!=S;i=to[path[i]]) {
            nf=min(nf,flow[path[i]^1]);
        }
        for(i=T;i!=S;i=to[path[i]]) {
            ans+=nf*val[path[i]^1];
            flow[path[i]^1]-=nf;
            flow[path[i]]+=nf;
        }
    }
    printf("%d
",ans);
}
int main() {
    scanf("%d%d",&n,&m);
    int i,j,k;
    for(i=1;i<=n;i++) scanf("%s",s[i]+1);
    for(i=1;i<=n;i++) {
        for(j=1;j<=m;j++) {
            add(S,p(i,j),1,0);
            add(p(i,j)+n*m,T,1,0);
            int p=0;
            if(s[i][j]=='R') p=0;
            else if(s[i][j]=='D') p=1;
            else if(s[i][j]=='L') p=2;
            else p=3;
            for(k=0;k<4;k++) {
                int di=i+tx[k],dj=j+ty[k];
                if(di==0) di=n; if(di==n+1) di=1;
                if(dj==0) dj=m; if(dj==m+1) dj=1;
                add(p(i,j),p(di,dj)+n*m,1,p!=k);
            }
        }
    }
    mcmf();
}

原文地址:https://www.cnblogs.com/suika/p/9127933.html