zoukankan      html  css  js  c++  java
  • BZOJ3171: [Tjoi2013]循环格

    3171: [Tjoi2013]循环格

    Time Limit: 1 Sec Memory Limit: 128 MB
    Submit: 1155 Solved: 730
    [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

    题解

    结论,n个点的有向图,只能连n条边,每个点都在回路内,当且仅当所有点出度入度都为1。
    先证充分, n条边,能够提供n个入度,n个出度,如果一个点入度大于1, 那么存在点的入度为0,走不出去,不能成回路。所以一个点入度必须为1。出度同理。
    再证必要,所有点出度入度都为1,所以只有一条路径可走。从一个点开始走,由于点数有限,若回不来,一定在某个地方走成了回路,那么入口处的点就会有两个入度,矛盾。

    一个点拆为两个,左边为出度点,右边为入度点。
    每个点改方向费用为1,不改费用为0.
    问题转化为二分图最小权完美匹配。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #include <cmath>
    inline int max(int a, int b){return a > b ? a : b;}
    inline int min(int a, int b){return a < b ? a : b;}
    inline int abs(int x){return x < 0 ? -x : x;}
    inline void swap(int &x, int &y){int tmp = x;x = y;y = tmp;}
    inline void read(int &x)
    {
        x = 0;char ch = getchar(), c = ch;
        while(ch < '0' || ch > '9') c = ch, ch = getchar();
        while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
        if(c == '-') x = -x;
    }
    const int INF = 0x3f3f3f3f;
    const int dx[4] = {0, 0, 1, -1};
    const int dy[4] = {1, -1, 0, 0};
    struct Edge
    {
    	int u,v,w,c,nxt;
    	Edge(int _u, int _v, int _w, int _c, int _nxt){u = _u;v = _v;w = _w;c = _c;nxt = _nxt;}
    	Edge(){}
    }edge[1000010];
    int head[1000010], cnt = 1, S, T, q[1000010], he, ta, d[1000010], vis[1000010], from[1000010], ans;
    inline void insert(int a, int b, int c, int d)
    {
    	edge[++ cnt] = Edge(a, b, c, d, head[a]), head[a] = cnt;
    	edge[++ cnt] = Edge(b, a, 0, -d, head[b]), head[b] = cnt;
    }
    bool spfa()
    {
    	memset(d, 0x3f, sizeof(d)), d[S] = 0, he = 0, ta = 1, q[0] = S, vis[S] = 1;
    	while(he < ta)
    	{
    		int now = q[he ++];if(he > 1000000) he = 0;
    		for(int pos = head[now];pos;pos = edge[pos].nxt)
    		{
    			int v = edge[pos].v;
    			if(edge[pos].w && d[v] > d[now] + edge[pos].c)
    			{
    				d[v] = d[now] + edge[pos].c, from[v] = pos;
    				if(!vis[v])
    				{
    					q[ta ++] = v;
    					if(ta > 1000000) ta = 0;
    				}
    			}
    		}
    		vis[now] = 0;
    	}
    	return d[T] != INF;
    }
    void flow()
    {
    	int mi = INF;
    	for(int i = from[T];i;i = from[edge[i].u]) mi = min(mi, edge[i].w);
    	for(int i = from[T];i;i = from[edge[i].u]) edge[i].w -= mi, edge[i ^ 1].w += mi, ans += edge[i].c * mi;
    }
    void mcf()
    {
    	while(spfa()) flow();
    }
    int n, m, num[101][101][2], tot; 
    char g[101][101];
    int main()
    {
    	read(n), read(m);
    	for(int i = 0;i < n;++ i)
    	{
    		scanf("%s", g[i]);
    		for(int j =0;j < m;++ j)
    			num[i][j][0] = ++ tot, num[i][j][1] = ++ tot;
    	}
    	S = tot + 1, T = S + 1;
    	//R L D U
    	for(int i = 0;i < n;++ i)
    		for(int j = 0;j < m;++ j)
    		{
    			insert(S, num[i][j][0], 1, 0), insert(num[i][j][1], T, 1, 0);
    			for(int k = 0;k < 4;++ k)
    			{
    				int val = 1, xx = (i + dx[k] + n) % n, yy = (j + dy[k] + m) % m;
    				if(k == 0 && g[i][j] == 'R') val = 0;
    				if(k == 1 && g[i][j] == 'L') val = 0;
    				if(k == 2 && g[i][j] == 'D') val = 0;
    				if(k == 3 && g[i][j] == 'U') val = 0;
    				insert(num[i][j][0], num[xx][yy][1], 1, val);
    			}
    		}
    	mcf();
    	printf("%d", ans);
        return 0;
    }
    
  • 相关阅读:
    Java SE之Java中堆内存和栈内存[转/摘]
    JavaSE之概述
    Java SE之字符串常量池
    Java SE之String,字符串和子字符串的存储与区别
    Java SE之基本程序设计结构
    Java SE关键字-static
    Java SE之初探反射机制
    Java SE之向上转型(动态绑定)与向下转型
    [C++]指针与引用(定义辨析)
    [C++]指针与引用(应用辨析)
  • 原文地址:https://www.cnblogs.com/huibixiaoxing/p/8521176.html
Copyright © 2011-2022 走看看