• bzoj3171 [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

    分析:
    很明显,图中只能有若干个环
    这就像一个欧拉回路一样,
    每个点的出度一定等于入度
    然而每个点的出度都是一,那也就是说入度一定是一
    这样就变成了怎么改变方向,使每个格子的出度和入度都等于一

    这就让我想起了有一道混合图的网络流题
    那道题就是让我们给每一条无向边定向,
    使得图成为一个欧拉路
    每改变一个格子的方向就会使两个格子的入度更改

    我一开始想的很简单:
    把每个点拆成两个点
    称作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;
    }
  • 相关阅读:
    SQL每日一题(20200512)
    SQL每日一题(20200506)
    SQL每日一题(20200509)
    sql每日一题(20200423)
    Oracle内存全面分析
    dbms_output.put与put_line
    oracle xml操作
    超级强大的破解极验滑动验证码--讲解非常详细
    python开发---目录
    Flask大全
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673280.html
Copyright © 2020-2023  润新知