• [UVA10859]放置街灯 Placing Lampposts


    题目

    点这里看题目。

    分析

    题目本身不难想,只需要在正常的 DP 外多加一个辅助状态即可求解附加问题。

    这个方法就不细讲了。重点说的是一个比较优雅的做法。

    考虑我们要最大化被两端覆盖的边的数量,也即是最小化只被一端覆盖的边的数量。现在我们就是同时最小化两个信息,并且存在优先级

    思考一下哪里存在天然的优先级?**数位!**如果我们把灯的数量压入高位,一端覆盖的边压入低位,对状态取 (min) 的时候,我们自然而然地满足了灯数量的优先。

    很巧妙吧。听到这个做法的时候,我也这样认为。

    具体而言,我们可以找到一个大于 (m) 的数 (K) ,并且将信息压成 (K) 进制的两位数,其中高位存灯、低位存边,然后就有:

    (f(u,0/1)):经过信息压缩的意义不变的状态。

    此时对状态$pm K$就相当于修改灯的数量,$pm1$就相当于修改边的数量。

    然后存在转移:

    [ egin{aligned} f(u,0)&=sum_v f(v,1)+1\ f(u,1)&=K+sum_v min{f(v,0)+1,f(v,1)} end{aligned} ]

    有意思吧。

    代码

    粗暴版本

    #include <cstdio>
    
    const int MAXN = 1e5 + 5, MAXM = 1e5 + 5;
    
    template<typename _T>
    void read( _T &x )
    {
    	x = 0;char s = getchar();int f = 1;
    	while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
    	while( s >= '0' && 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 ) + 1; }
    	if( 9 < x ){ write( x / 10 ); }
    	putchar( x % 10 + '0' );
    }
    
    template<typename _T>
    _T MAX( const _T a, const _T b )
    {
    	return a > b ? a : b;
    }
    
    struct edge
    {
    	int to, nxt;
    }Graph[MAXN << 1];
    
    int f[MAXN][2], g[MAXN][2];
    int head[MAXN];
    int N, M, cnt;
    bool vis[MAXN];
    
    void addEdge( const int from, const int to )
    {
    	Graph[++ cnt].to = to, Graph[cnt].nxt = head[from];
    	head[from] = cnt;
    }
    
    void DFS( const int u, const int fa )
    {
    	vis[u] = true;
    	f[u][0] = 0, f[u][1] = 1;
    	g[u][0] = g[u][1] = 0;
    	for( int i = head[u], v ; i ; i = Graph[i].nxt )
    		if( ( v = Graph[i].to ) ^ fa )
    		{
    			DFS( v, u );
    			f[u][0] += f[v][1], g[u][0] += g[v][1];
    			if( f[v][1] < f[v][0] ) f[u][1] += f[v][1], g[u][1] += g[v][1] + 1;
    			else if( f[v][1] > f[v][0] ) f[u][1] += f[v][0], g[u][1] += g[v][0];
    			else f[u][1] += f[v][1], g[u][1] += MAX( g[v][1] + 1, g[v][0] );
    		}
    }
    
    void clr()
    {
    	cnt = 0;
    	for( int i = 1 ; i <= N ; i ++ ) 
    		vis[i] = head[i] = 0;
    }
    
    int main()
    {
    	int T;
    	read( T );
    	while( T -- )
    	{
    		int ans1 = 0, ans2 = 0;
    		read( N ), read( M ), clr();
    		for( int i = 1, a, b ; i <= M ; i ++ )
    			read( a ), read( b ), a ++, b ++,
    			addEdge( a, b ), addEdge( b, a );
    		for( int i = 1 ; i <= N ; i ++ )
    			if( ! vis[i] )
    			{
    				DFS( i, 0 );
    				if( f[i][0] < f[i][1] ) ans1 += f[i][0], ans2 += g[i][0];
    				else if( f[i][0] > f[i][1] ) ans1 += f[i][1], ans2 += g[i][1];
    				else ans1 += f[i][0], ans2 += MAX( g[i][0], g[i][1] );
    			}
    		write( ans1 ), putchar( ' ' ), write( ans2 ), putchar( ' ' ), write( M - ans2 ), putchar( '
    ' );
    	}
    	return 0;
    }
    

    优雅版本

    #include <cstdio>
    
    const int K = 1e3;
    const int MAXN = 1e5 + 5, MAXM = 1e5 + 5;
    
    template<typename _T>
    void read( _T &x )
    {
    	x = 0;char s = getchar();int f = 1;
    	while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
    	while( s >= '0' && 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 ) + 1; }
    	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;
    }
    
    struct edge
    {
    	int to, nxt;
    }Graph[MAXN << 1];
    
    int f[MAXN][2];
    int head[MAXN];
    int N, M, cnt;
    bool vis[MAXN];
    
    void addEdge( const int from, const int to )
    {
    	Graph[++ cnt].to = to, Graph[cnt].nxt = head[from];
    	head[from] = cnt;
    }
    
    void DFS( const int u, const int fa )
    {
    	vis[u] = true;
    	f[u][0] = 0, f[u][1] = K;
    	for( int i = head[u], v ; i ; i = Graph[i].nxt )
    		if( ( v = Graph[i].to ) ^ fa )
    		{
    			DFS( v, u );
    			f[u][0] += f[v][1] + 1;
    			f[u][1] += MIN( f[v][1], f[v][0] + 1 );
    		}
    }
    
    void clr()
    {
    	cnt = 0;
    	for( int i = 1 ; i <= N ; i ++ ) 
    		vis[i] = head[i] = 0;
    }
    
    int main()
    {
    	int T;
    	read( T );
    	while( T -- )
    	{
    		int ans1 = 0, ans2 = 0;
    		read( N ), read( M ), clr();
    		for( int i = 1, a, b ; i <= M ; i ++ )
    			read( a ), read( b ), a ++, b ++,
    			addEdge( a, b ), addEdge( b, a );
    		for( int i = 1 ; i <= N ; i ++ )
    			if( ! vis[i] )
    			{
    				DFS( i, 0 );
    				int tmp = MIN( f[i][0], f[i][1] );
    				ans1 += tmp / K;
    				ans2 += tmp % K;
    			}
    		write( ans1 ), putchar( ' ' ), write( M - ans2 ), putchar( ' ' ), write( ans2 ), putchar( '
    ' );
    	}
    	return 0;
    }
    
  • 相关阅读:
    SOJ 4580 动态规划之01背包 (01背包)
    文件比较与同步工具——FreeFileSync
    肺结节CT影像特征提取(五)——肺结节CT影像ROI区域灰度直方图及其图形化
    JAVA学习笔记(4)—— 排序算法
    JAVA学习笔记(3)—— 抽象类与接口
    JAVA学习笔记(2)—— java初始化三个原则
    JAVA学习笔记(1)—— eclipse自动补全和主题及字体配置
    3D Slicer中文教程(八)—导出STL文件
    3D Slicer中文教程(七)—图像中值滤波
    “Excel-建议不可用于您所选择的数据”错误提示
  • 原文地址:https://www.cnblogs.com/crashed/p/13404607.html
Copyright © 2020-2023  润新知