zoukankan      html  css  js  c++  java
  • 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();
    }
    
    
  • 相关阅读:
    创建进程
    进程
    操作系统历史
    socket
    网络基础
    常用模块二:hashlib、configparser、logging
    常见正则匹配
    类中的内置方法(魔法方法、双下方法)
    反射、isinstance和issubclass
    封装、继承、多态
  • 原文地址:https://www.cnblogs.com/suika/p/9127933.html
Copyright © 2011-2022 走看看