列表

详情


NC51253. 巡逻

描述

在一个地区有 n 个村庄,编号为1,2,…,n。有 n-1 条道路连接着这些村庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以通过这些道路到达其他任一个村庄。

每条道路的长度均为1个单位。

为保证该地区的安全,巡警车每天都要到所有的道路上巡逻。警察局设在编号为1的村庄里,每天巡警车总是从警局出发,最终又回到警局。
下图表示一个有8个村庄的地区,其中村庄用圆表示(其中村庄1用黑色的圆表示),道路是连接这些圆的线段;为了遍历所有的道路,巡警车需要走的距离为14个单位,每条道路都需要经过两次:

为了减少总的巡逻距离,该地区准各在这些村庄之间建立K条新的道路,每条新道路可以连接任意两个村庄:两条新道路可以在同一个村庄会合或结束(见下面的图例(c))-一条新道路甚至可以是一个环,即,其两端连接到同一个村庄:由于资金有限,K只能是]或2:同时,为了不浪费资金,每天巡警车必须经过新建的道路正好一次:
下图给出了一些建立新道路的例子:


在(a)中,新建了一条道路,总的距离是Il:在(b)中,新建了两条道路,总的巡逻距离是10:在(c)中,新建了两条道路,但由于巡警车要经过每条新道路正好一次,总的距离变为了巧:
试编写一个程序,读取村庄间道路的信息和需要新建的道路数,计算出最佳的新建道路的方案使得总的巡逻距离最小,并输出这个最小的巡逻距离:

输入描述

第一行包含两个整数。接下来 n – 1行,每行两个整数 a, b, 表示村庄a与b之间有一条道路

输出描述

输出一个整数,表示新建了K 条道路后能达到的最小巡逻距离。

示例1

输入:

8 1 
1 2 
3 1 
3 4 
5 3 
7 5 
8 5 
5 6 

输出:

11

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 57ms, 内存消耗: 4836K, 提交时间: 2019-09-11 20:31:45

//Author:XuHt
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100006;
int n, k, d[N], fa[N];
int Head[N], Edge[N<<1], Leng[N<<1], Next[N<<1], tot = 1;
bool v[N];

void add(int x, int y, int z) {
	Edge[++tot] = y;
	Leng[tot] = z;
	Next[tot] = Head[x];
	Head[x] = tot;
}

void dfs(int x, int &t) {
	v[x] = 1;
	for (int i = Head[x]; i; i = Next[i]) {
		int y = Edge[i], z = Leng[i];
		if (v[y]) continue;
		if ((d[y] = d[x] + z) >= d[t]) t = y;
		fa[y] = i;
		dfs(y, t);
	}
	v[x] = 0;
}

void dp(int x, int &t) {
	v[x] = 1;
	for (int i = Head[x]; i; i = Next[i]) {
		int y = Edge[i], z = Leng[i];
		if (v[y]) continue;
		dp(y, t);
		t = max(t, d[x] + d[y] + z);
		d[x] = max(d[x], d[y] + z);
	}
}

int main() {
	cin >> n >> k;
	for (int i = 1; i < n; i++) {
		int x, y;
		scanf("%d %d", &x, &y);
		add(x, y, 1);
		add(y, x, 1);
	}
	int t = 1;
	dfs(1, t);
	d[t] = fa[t] = 0;
	int tt = t;
	dfs(t, tt);
	int ans = ((n - 1) << 1) - d[tt] + 1;
	if (k == 2) {
		while (fa[tt]) {
			Leng[fa[tt]] = Leng[fa[tt]^1] = -1;
			tt = Edge[fa[tt]^1];
		}
		tt = 0;
		memset(d, 0, sizeof(d));
		dp(t, tt);
		ans -= tt - 1;
	}
	cout << ans << endl;
	return 0;
}

C++(clang++11) 解法, 执行用时: 30ms, 内存消耗: 6172K, 提交时间: 2020-11-03 13:45:05

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int M=1e5+10;
struct bian{int y,gg,c;}b[M<<1];
int len=1,h[M],f[M][2],d[M];
void ins(int x,int y)
{
	b[++len].y=y;b[len].c=1;
	b[len].gg=h[x];h[x]=len;
}

int maxx=0,id;
void dfs(int x,int fa)
{
	for(int i=h[x];i;i=b[i].gg)
	{
		int y=b[i].y;
		if(y==fa)continue;
		d[y]=max(d[y],d[x]+b[i].c);
		if(d[y]>maxx)maxx=d[y],id=y;
		f[y][0]=x;f[y][1]=i;
		dfs(y,x);
		
	}
}

void dp(int x,int fa)
{
	for(int i=h[x];i;i=b[i].gg)
	{
		int y=b[i].y;
		if(y==fa)continue;
		dp(y,x);
		maxx=max(maxx,d[y]+d[x]+b[i].c);
		d[x]=max(d[x],d[y]+b[i].c);
	}
}

int main()
{
	int n,k;scanf("%d %d",&n,&k);
	for(int i=1;i<n;i++)
	{
		int x,y;scanf("%d %d",&x,&y);
		ins(x,y);ins(y,x);
	}
	dfs(1,-1);
	maxx=0;
	int st=id;
	memset(d,0,sizeof(d));
	dfs(st,0);
	f[st][0]=0;
	int ed=id,ans=((n-1)<<1)-maxx+1;
	if(k==2)
	{
		maxx=0;
		memset(d,0,sizeof(d));
		for(int i=ed;i;i=f[i][0])
			b[f[i][1]].c=b[f[i][1]^1].c=-1;
		dp(1,-1);
		ans-=maxx-1;
	}
	printf("%d\n",ans);
	return 0;
}

上一题