bzoj1912 [Apio2010]patrol 巡逻
2018-03-06 09:40
204 查看
http://www.elijahqi.win/2018/03/06/bzoj1912/
题目描述
在一个地区中有 n 个村庄,编号为 1, 2, …, n。有 n – 1 条道路连接着这些村 庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以通过这些道路到达其 他任一个村庄。每条道路的长度均为 1 个单位。 为保证该地区的安全,巡警车每天要到所有的道路上巡逻。警察局设在编号 为 1 的村庄里,每天巡警车总是从警察局出发,最终又回到警察局。 下图表示一个有 8 个村庄的地区,其中村庄用圆表示(其中村庄 1 用黑色的 圆表示),道路是连接这些圆的线段。为了遍历所有的道路,巡警车需要走的距 离为 14 个单位,每条道路都需要经过两次。
为了减少总的巡逻距离,该地区准备在这些村庄之间建立 K 条新的道路, 每条新道路可以连接任意两个村庄。两条新道路可以在同一个村庄会合或结束 (见下面的图例(c))。 一条新道路甚至可以是一个环,即,其两端连接到同一 个村庄。 由于资金有限,K 只能是 1 或 2。同时,为了不浪费资金,每天巡警车必须 经过新建的道路正好一次。 下图给出了一些建立新道路的例子:
在(a)中,新建了一条道路,总的距离是 11。在(b)中,新建了两条道路,总 的巡逻距离是 10。在(c)中,新建了两条道路,但由于巡警车要经过每条新道路 正好一次,总的距离变为了 15。 试编写一个程序,读取村庄间道路的信息和需要新建的道路数,计算出最佳 的新建道路的方案使得总的巡逻距离最小,并输出这个最小的巡逻距离。
输入输出格式
输入格式:
第一行包含两个整数 n, K(1 ≤ K ≤ 2)。接下来 n – 1 行,每行两个整数 a, b, 表示村庄 a 与 b 之间有一条道路(1 ≤ a, b ≤ n)。
输出格式:
输出一个整数,表示新建了 K 条道路后能达到的最小巡逻距离。
输入输出样例
输入样例#1: 复制
8 1
1 2
3 1
3 4
5 3
7 5
8 5
5 6
输出样例#1: 复制
11
输入样例#2: 复制
8 2
1 2
3 1
3 4
5 3
7 5
8 5
5 6
输出样例#2: 复制
10
输入样例#3: 复制
5 2
1 2
2 3
3 4
4 5
输出样例#3: 复制
6
说明
10%的数据中,n ≤ 1000, K = 1;
30%的数据中,K = 1;
80%的数据中,每个村庄相邻的村庄数不超过 25;
90%的数据中,每个村庄相邻的村庄数不超过 150; 100%的数据中,3 ≤ n ≤ 100,000, 1 ≤ K ≤ 2。
k=1两遍直接求最长链即可
k=2 将直径改成-1 然后求最长链 为什么因为无可避免的 曾经走一次的道路 现在不得不重新走两次 那么好办 改成树形dp 类似点分过根的写法 再求一下最长链
为什么我的dfs1 mx1,mx2给的0 因为如果是负数不妨给自环
copy icefox 巨佬的题解 希望它不要打我..
显然答案一开始是n-1<<1,每条边都要走两遍。
如果K=1,可以新建一条道路,那么应该把树上最长链的两端连起来,这样就不用走两遍树上最长链了,而是只需要走一遍,(通过新边直接过去,不需要再返回了)。因此答案就是减去树上最长链+1。
如果K=2,还可以再新建一条,那么我们发现如果这次选择的链和上次选择的最长链有交集,则这一部分的边还是要走两遍,因此我们把最长链上的边权均变为-1,再求树上最长链,答案再减去此时树上最长链+1。
因为有负权,所以我们只能树形dp来求。
题目描述
在一个地区中有 n 个村庄,编号为 1, 2, …, n。有 n – 1 条道路连接着这些村 庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以通过这些道路到达其 他任一个村庄。每条道路的长度均为 1 个单位。 为保证该地区的安全,巡警车每天要到所有的道路上巡逻。警察局设在编号 为 1 的村庄里,每天巡警车总是从警察局出发,最终又回到警察局。 下图表示一个有 8 个村庄的地区,其中村庄用圆表示(其中村庄 1 用黑色的 圆表示),道路是连接这些圆的线段。为了遍历所有的道路,巡警车需要走的距 离为 14 个单位,每条道路都需要经过两次。
为了减少总的巡逻距离,该地区准备在这些村庄之间建立 K 条新的道路, 每条新道路可以连接任意两个村庄。两条新道路可以在同一个村庄会合或结束 (见下面的图例(c))。 一条新道路甚至可以是一个环,即,其两端连接到同一 个村庄。 由于资金有限,K 只能是 1 或 2。同时,为了不浪费资金,每天巡警车必须 经过新建的道路正好一次。 下图给出了一些建立新道路的例子:
在(a)中,新建了一条道路,总的距离是 11。在(b)中,新建了两条道路,总 的巡逻距离是 10。在(c)中,新建了两条道路,但由于巡警车要经过每条新道路 正好一次,总的距离变为了 15。 试编写一个程序,读取村庄间道路的信息和需要新建的道路数,计算出最佳 的新建道路的方案使得总的巡逻距离最小,并输出这个最小的巡逻距离。
输入输出格式
输入格式:
第一行包含两个整数 n, K(1 ≤ K ≤ 2)。接下来 n – 1 行,每行两个整数 a, b, 表示村庄 a 与 b 之间有一条道路(1 ≤ a, b ≤ n)。
输出格式:
输出一个整数,表示新建了 K 条道路后能达到的最小巡逻距离。
输入输出样例
输入样例#1: 复制
8 1
1 2
3 1
3 4
5 3
7 5
8 5
5 6
输出样例#1: 复制
11
输入样例#2: 复制
8 2
1 2
3 1
3 4
5 3
7 5
8 5
5 6
输出样例#2: 复制
10
输入样例#3: 复制
5 2
1 2
2 3
3 4
4 5
输出样例#3: 复制
6
说明
10%的数据中,n ≤ 1000, K = 1;
30%的数据中,K = 1;
80%的数据中,每个村庄相邻的村庄数不超过 25;
90%的数据中,每个村庄相邻的村庄数不超过 150; 100%的数据中,3 ≤ n ≤ 100,000, 1 ≤ K ≤ 2。
k=1两遍直接求最长链即可
k=2 将直径改成-1 然后求最长链 为什么因为无可避免的 曾经走一次的道路 现在不得不重新走两次 那么好办 改成树形dp 类似点分过根的写法 再求一下最长链
为什么我的dfs1 mx1,mx2给的0 因为如果是负数不妨给自环
copy icefox 巨佬的题解 希望它不要打我..
显然答案一开始是n-1<<1,每条边都要走两遍。
如果K=1,可以新建一条道路,那么应该把树上最长链的两端连起来,这样就不用走两遍树上最长链了,而是只需要走一遍,(通过新边直接过去,不需要再返回了)。因此答案就是减去树上最长链+1。
如果K=2,还可以再新建一条,那么我们发现如果这次选择的链和上次选择的最长链有交集,则这一部分的边还是要走两遍,因此我们把最长链上的边权均变为-1,再求树上最长链,答案再减去此时树上最长链+1。
因为有负权,所以我们只能树形dp来求。
#include<cstdio> #include<algorithm> #define N 110000 #define inf 0x3f3f3f3f using namespace std; inline char gc(){ static char now[1<<16],*S,*T; if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;} return *S++; } inline int read(){ int x=0,f=1;char ch=gc(); while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();} while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc(); return x*f; } struct node{ int y,next,z; }data[N<<1]; int h ,num=1,ed,n,k,dis ,pos,max1,len; inline void dfs(int x,int fa){ for (int i=h[x];i;i=data[i].next){ int y=data[i].y;if (y==fa) continue; dis[y]=dis[x]+data[i].z;if (dis[y]>max1) max1=dis[y],pos=y;dfs(y,x); } } inline bool mark(int x,int fa){ if (x==ed) return 1;bool flag=0; for (int i=h[x];i;i=data[i].next){ int y=data[i].y;if (y==fa) continue; if (mark(y,x)) {flag=1,data[i].z=-1,data[i^1].z=-1;return flag;} }return flag; }int ans; inline int dfs1(int x,int fa){ int mx1=0,mx2=0,tmp=0; for (int i=h[x];i;i=data[i].next){ int y=data[i].y,z=data[i].z;if (y==fa) continue; tmp=dfs1(y,x);tmp+=z; if (tmp>mx1) mx2=mx1,mx1=tmp;else if (tmp>mx2) mx2=tmp; }ans=max(ans,mx1+mx2);return mx1; } int main(){ freopen("bzoj1912.in","r",stdin); n=read();k=read(); for (int i=1;i<n;++i){ int x=read(),y=read(); data[++num].y=y;data[num].z=1;data[num].next=h[x];h[x]=num; data[++num].y=x;data[num].z=1;data[num].next=h[y];h[y]=num; }dfs(1,1);int st=pos;max1=-inf;dis[st]=0;dfs(st,st);ed=pos;len=max1; if (k==1) {printf("%d\n",(n-1)*2+1-len);return 0;}mark(st,st); dfs1(1,1);printf("%d\n",(n-1)*2+2-len-ans); return 0; }
相关文章推荐
- [bzoj1912][Apio2010]patrol 巡逻(树上dp)
- 【BZOJ】【1912】【APIO2010】patrol巡逻
- bzoj1912 [Apio2010]patrol 巡逻
- [BZOJ1912][Apio2010]patrol 巡逻(dfs+并查集+树形dp)
- [BZOJ1912][Apio2010]patrol 巡逻(树上最长链)
- bzoj 1912: [Apio2010]patrol 巡逻
- [BZOJ 1912][Apio2010]patrol 巡逻:树的直径
- BZOJ 1912 [Apio2010]patrol 巡逻
- BZOJ1912 [Apio2010]patrol 巡逻
- bzoj1912 [Apio2010]patrol 巡逻(dp求树上最长链)
- 【BZOJ 1912】 [Apio2010]patrol 巡逻
- 【bzoj1912】[Apio2010]patrol 巡逻
- bzoj 1912: [Apio2010]patrol 巡逻【不是dp是枚举+堆】
- BZOJ1912[Apio2010]patrol 巡逻
- 【bzoj1912】 Apio2010—patrol 巡逻
- [BZOJ 1912][APIO 2010]patrol 巡逻(树的直径)
- 【bzoj1912】 APIO2010patrol巡逻 树的直径
- BZOJ1912[Apio2010]patrol 巡逻
- bzoj1912 [Apio2010]patrol 巡逻(树的直径[变式])
- bzoj 1912 [Apio2010]patrol 巡逻 树形dp