zoukankan      html  css  js  c++  java
  • [CF1368H1]Breadboard Capacity (easy version)

    题目

    点这里看题目。

    分析

    首先,不难发现此题可以方便地建出网络流的图来。图中的每个节点向周围四个点连一条容量为 1 的无向边,然后 (S) 连向红色接口, (T) 连向蓝色接口。

    原题的答案便是此图上的最大流。显然原问题没法做,我们直接上最小割

    最小割本质上就是要将点拆分成两个点集。为了方便,我们就将 (S) 集合中的点染成红色(T) 集合中的染成蓝色

    那么原图中的最小割就等于两端点颜色不同的边的数量

    考虑内部的 (n imes m) 个点应该如何最小化这种边的数量。仍然是为了方便,我们给异色端点的边上划一道垂直的虚线,考虑这样的虚线连为的路径。

    pg1.png

    如上图。假如电路板的内部出现了一个环,很显然我们应该改变内部点的颜色,消除它。这样答案不会变劣。

    pg2.png

    如上图。假如电路板内部出现了连接相邻的两个边界或者同一个边界的路径,我们显然应该改变它们的颜色,消除它们。这样答案不会变劣。

    pg3.png

    如上图。假如电路板内部出现了连接相对的两个边界的路径,我们同样可以改变它们的颜色,并且把它们拉直,使得它们在非边界的位置不拐弯。

    因此,这样操作之后,图上就只会在列上或者行上存在连接相对边界的不拐弯的路径

    行列本身是类似的,单独考虑列。最终的最优情况就是所有列的颜色相同

    这个问题就可以用一个简单的 DP 来处理了:

    (f(i,0/1)):前 (i) 行,颜色为 (0) (表示蓝色)或者 (1) (表示红色)时的最小割。

    转移略。对行和列都做一遍,对所有的情况取 (min) 就是最小割,即答案。

    关于 H2 ,由于 DP 的第二位很小,因此可以用矩阵来表示转移。这样就可以用线段树维护转移矩阵,单次修改是 (O(log_2n)) 的。

    小结:

    1. 将问题建出对应的网络来,并且将最大流转换成最小割,将最小割转换成染色问题
    2. 染色问题转化为了类似于周长的问题,压缩最优解的情况

    代码

    #include <cstdio>
    #include <iostream>
    using namespace std;
    
    const int MAXN = 1e5 + 5;
    
    template<typename _T>
    void read( _T &x )
    {
    	x = 0; char s = getchar(); int f = 1;
    	while( s < '0' || '9' < s ) { f = 1; if( s == '-' ) f = -1; s = getchar(); }
    	while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ); s = getchar(); }
    	x *= f;
    }
    
    template<typename _T>
    void write( _T x )
    {
    	if( x < 0 ) putchar( '-' ), x = -x;
    	if( 9 < x ) write( x / 10 );
    	putchar( x % 10 + '0' );
    }
    
    template<typename _T>
    _T MIN( const _T a, const _T b )
    {
    	return a < b ? a : b;
    }
    
    char S[MAXN];
    int up[MAXN], down[MAXN], lef[MAXN], rig[MAXN];
    int N, M, Q;
    
    void Get( const int n, int *a )
    {
    	scanf( "%s", S + 1 );
    	for( int i = 1 ; i <= n ; i ++ ) 
    		a[i] = S[i] == 'R';
    }
    
    int Calc()
    {
    	int f0 = 0, f1 = 0, n0, n1;
    	for( int i = 1 ; i <= M ; i ++ ) f0 += up[i], f1 += ! up[i];
    	for( int i = 1 ; i <= N ; i ++ )
    	{
    		n0 = MIN( f0, f1 + M ) + lef[i] + rig[i];
    		n1 = MIN( f0 + M, f1 ) + ( ! lef[i] ) + ( ! rig[i] );
    		f0 = n0, f1 = n1;
    	}
    	for( int i = 1 ; i <= M ; i ++ ) f0 += down[i], f1 += ! down[i]; 
    	return MIN( f0, f1 );
    }
    
    int main()
    {
    	read( N ), read( M ), read( Q );
    	Get( N, lef ), Get( N, rig );
    	Get( M, up ), Get( M, down );
    	
    	int ans1 = Calc(), ans2;
    	swap( N, M ), swap( up, lef ), swap( down, rig );
    	ans2 = Calc();
    	
    	write( MIN( ans1, ans2 ) ), putchar( '
    ' );
    	return 0;
    }
    
  • 相关阅读:
    只要你拥有爱心,你就会拥有快乐。
    解决升级 Office 2010 之后 Outlook 提示“无法打开 Microsoft Outlook”
    《老人与海》
    UML模型的组成
    2009年11月11日
    IBatis存取图片在Oracle Blob大字段中Asp.Net
    “北京今年入冬的第一场雪”,纪念博客园写日志一年了
    UML建模实践概述
    UML 类图
    UML 用例图
  • 原文地址:https://www.cnblogs.com/crashed/p/13811409.html
Copyright © 2011-2022 走看看