[UVA10859]放置街灯 Placing Lampposts

题目

点这里看题目。

分析

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

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

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

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

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

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

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

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

然后存在转移:

\[\begin{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( '\n' );
	}
	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( '\n' );
	}
	return 0;
}
posted @ 2020-07-30 16:30  crashed  阅读(198)  评论(0编辑  收藏  举报