【题解】P3629 [APIO2010]巡逻

link

题意

\(n\) 个村庄,编号为 \(1, 2, ..., n\) 。有 \(n – 1\) 条道路连接着这些村 庄,从任何一个村庄都可以到达其他任一个村庄。道路长度均为 1。 巡警车每天要到所有的道路上巡逻。警察局设在编号为 \(1\) 的村庄里,每天巡警车总是从警察局出发又回到警察局。

在这些村庄之间建 \(K\) 条新的道路, 可以连接任意两个村庄。每天巡警车必须 经过新建的道路正好一次. 求最小的巡逻距离。

思路

非常有意思的一道题。顺便复习了直径的两种写法。

考虑逐条加边。

如果不加边,那么答案显然是 \(2(n-1)\).

如果加一条边,由于必须经过恰好一次,所以在沿着新的道路 \((u,v)\) 走了一次之后,要返回 \(u\) ,必须沿着树上的环的另一半再走一遍,那么这时候 \(u\to v\) 的路径只需要走一次,所以 \(ans=2(n-1)-L-+1.\)

再加一条边,如果环没有重叠,那么按照一条的情况处理即可。否则,重叠部分不会被走过,所以还要走一次,又变成了需要走两次的边。

总结两种情况,得到算法:

  1. 找一遍直径,边权取反,长度为 \(L_1\)
  2. 再求直径,得到 \(L_2\)
  3. \(ans=2(n-1)-(L_1-1)-(L_2-1)\)

代码

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct edge
{
        int to,nxt,val;
}e[N<<1];
int n,k,tot=0,mx,head[N],dis[N],pre[N],f[N];
bool vis[N];
queue<int> q;

void add( int u,int v,int w )
{
        e[++tot].to=v; e[tot].val=w; e[tot].nxt=head[u]; head[u]=tot;
}

int bfs( int s )
{
	memset( dis,0x3f,sizeof(dis) );
	q.push( s ); dis[s]=pre[s]=0;
	while ( q.size() )
	{
		int t=q.front(); q.pop();
		for ( int i=head[t]; i; i=e[i].nxt )
			if ( dis[e[i].to]==0x3f3f3f3f )
				dis[e[i].to]=dis[t]+e[i].val,pre[e[i].to]=i,q.push( e[i].to );
	}
	int res=1;
	for ( int x=1; x<=n; x++ )
		if ( dis[x]>dis[res] ) res=x;
	return res;
}

void dp( int x )
{
	vis[x]=1; 
	for ( int i=head[x]; i; i=e[i].nxt )
		if ( !vis[e[i].to] )
		{
                        dp( e[i].to );
                        mx=max( mx,f[e[i].to]+f[x]+e[i].val );
                        f[x]=max( f[x],f[e[i].to]+e[i].val ); 
		}
}

int main()
{
	memset( head,0,sizeof(head) ); tot=1;

	scanf( "%d%d",&n,&k );
	for ( int i=1,u,v; i<n; i++ )
		scanf( "%d%d",&u,&v ),add( u,v,1 ),add( v,u,1 );
        
        int l=bfs( 1 ); l=bfs(l);
        int L1=dis[l],fl=1; mx=0;
        if ( k==2 )
        {
                for ( ; pre[l]; l=e[pre[l]^1].to )
                        e[pre[l]].val=e[pre[l]^1].val=-1;
                dp( 1 ); fl=2;
        }
        printf( "%d",2*(n-1)-L1-mx+fl );

        return 0;
}
posted @ 2020-11-02 16:11  MontesquieuE  阅读(70)  评论(0编辑  收藏  举报