bzoj3171 [Tjoi2013]循环格

Posted zbtrs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj3171 [Tjoi2013]循环格相关的知识,希望对你有一定的参考价值。

3171: [Tjoi2013]循环格

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 1169  Solved: 736
[Submit][Status][Discuss]

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,入度为1. 如果把每个点拆成两个点:入点和出点.  对于出点,由源点向其连一条容量为1的边,对于入点,由其向汇点连一条容量为1的边. 这样满流的时候,所有点的入度和出度就都是1了.

   接下来考虑点与点之间的连边. 考虑每一对相邻的点.对于原图中存在的边,从出点连向入点,费用为0,如果如果边不存在(由存在的边旋转得到),则费用为1.

   有了S和T流量的限制,就能满足要求,并且使得费用最小了.

   注意:数组要开大! 计算边数一定不要忘了计算反向边! 一个好的方法是看每一个循环中出现了多少条连边语句,总和乘2就是边数了.

#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 1010,inf = 0x7fffffff,dx[] = {0,0,1,-1},dy[] = {1,-1,0,0};
int n,m,S,T,ans,head[maxn],to[maxn * 20],nextt[maxn * 20],w[maxn * 20],cost[maxn * 20],tot = 2;
char s[maxn][maxn];
int vis[maxn],vis2[maxn],d[maxn];

void add(int x,int y,int z,int p)
{
    cost[tot] = p;
    w[tot] = z;
    to[tot] = y;
    nextt[tot] = head[x];
    head[x] = tot++;

    cost[tot] = -p;
    w[tot] = 0;
    to[tot] = x;
    nextt[tot] = head[y];
    head[y] = tot++;
}

bool spfa()
{
    for (int i = 1; i <= T; i++)
        d[i] = inf;
    memset(vis,0,sizeof(vis));
    memset(vis2,0,sizeof(vis2));
    d[S] = 0;
    vis[S] = 1;
    queue <int> q;
    q.push(S);
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for (int i = head[u];i;i = nextt[i])
        {
            int v = to[i];
            if (w[i] && d[v] > d[u] + cost[i])
            {
                d[v] = d[u] + cost[i];
                if (!vis[v])
                {
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
    }
    return d[T] < inf;
}

int dfs(int u,int f)
{
    if (u == T)
    {
        ans += d[u] * f;
        return f;
    }
    int res = 0;
    vis2[u] = 1;
    for (int i = head[u];i;i = nextt[i])
    {
        int v = to[i];
        if (!vis2[v] && w[i] && d[v] == d[u] + cost[i])
        {
            int temp = dfs(v,min(f - res,w[i]));
            w[i] -= temp;
            w[i ^ 1] += temp;
            res += temp;
            if (res == f)
                return res;
        }
    }
    return res;
}

void dinic()
{
    while (spfa())
        dfs(S,inf);
}

int calc(int x,int y)
{
    return (x - 1) * m + y;
}

int main()
{
    scanf("%d%d",&n,&m);
    S = n * m * 2 + 1;
    T = S + 1;
    for (int i = 1; i <= n; i++)
        scanf("%s",s[i] + 1);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
        {
            int ti = i,tj = j;
            if (s[i][j] == R)
                tj++;
            if (s[i][j] == L)
                tj--;
            if (s[i][j] == U)
                ti--;
            if (s[i][j] == D)
                ti++;
            if (tj == m + 1)
                tj = 1;
            if (tj == 0)
                tj = m;
            if (ti == n + 1)
                ti = 1;
            if (ti == 0)
                ti = n;
            int temp = calc(i,j),temp2 = calc(ti,tj);
            add(S,temp + n * m,1,0);
            add(temp,T,1,0);
            add(temp + n * m,temp2,1,0);
            for (int k = 0; k < 4; k++)
            {
                int di = i + dx[k],dj = j + dy[k];
                if (dj == m + 1)
                    dj = 1;
                if (dj == 0)
                    dj = m;
                if (di == n + 1)
                    di = 1;
                if (di == 0)
                    di = n;
                if (di == ti && dj == tj)
                    continue;
                int temp3 = calc(di,dj);
                add(temp + n * m,temp3,1,1);
            }
        }
    dinic();
    printf("%d\n",ans);

    return 0;
}

 

以上是关于bzoj3171 [Tjoi2013]循环格的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 3171 [Tjoi2013]循环格(MCMF)

bzoj 3171: [Tjoi2013]循环格

BZOJ 3171 [Tjoi2013]循环格

bzoj3171 [Tjoi2013]循环格

bzoj:3171: [Tjoi2013]循环格

bzoj3171: [Tjoi2013]循环格