1912: [Apio2010]patrol 巡逻
Time Limit: 4 Sec Memory Limit: 64 MB
Submit: 1034 Solved: 562
[Submit][Status][Discuss]
Description
Input
第一行包含两个整数 n, K(1 ≤ K ≤ 2)。接下来 n – 1行,每行两个整数 a, b, 表示村庄a与b之间有一条道路(1 ≤ a, b ≤ n)。
Output
输出一个整数,表示新建了K 条道路后能达到的最小巡逻距离。
Sample Input
8 1
1 2
3 1
3 4
5 3
7 5
8 5
5 6
Sample Output
11
HINT
10%的数据中,n ≤ 1000, K = 1;
30%的数据中,K = 1;
80%的数据中,每个村庄相邻的村庄数不超过 25;
90%的数据中,每个村庄相邻的村庄数不超过 150;
100%的数据中,3 ≤ n ≤ 100,000, 1 ≤ K ≤ 2。
Source
Solution
发现加边实际上就是形成环,使得一条路径可以直接绕回来,不用原路返回
那么K==1的时候,边一定用来连最长的路径(树的直径)那么DFS出即可
K==2的时候同理,不过需要次短,同样DFS,对第一次DFS求得的路径做些修改,置成-1就可以
Code
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; int read() { int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } #define maxn 100010 int n,k,ans,zj,s; struct EdgeNode{int next,to,len;}edge[maxn<<1]; int head[maxn],cnt=1;int road[maxn]={0},croad[maxn]={0}; void add(int u,int v,int w) { cnt++; edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].len=w; } void insert(int u,int v,int w) {add(u,v,w); add(v,u,w);} int DFS(int now,int fa) { int maxd=0,cmaxd=0; for (int i=head[now]; i; i=edge[i].next) if (edge[i].to!=fa) { int len=DFS(edge[i].to,now)+edge[i].len; if (len>maxd) cmaxd=maxd,maxd=len,croad[now]=road[now],road[now]=i; else if (len>cmaxd) cmaxd=len,croad[now]=i; } if (maxd+cmaxd>zj) zj=maxd+cmaxd,s=now; // printf("%d %d %d %d\n",now,fa,maxd,cmaxd); return maxd; } int main() { n=read(); k=read(); for (int u,v,i=1; i<=n-1; i++) u=read(),v=read(),insert(u,v,1); DFS(1,0); ans=2*(n-1)-zj+1; if (k==2) { for (int i=road[s]; i; i=road[edge[i].to]) edge[i].len=edge[i^1].len=-1; for (int i=croad[s]; i; i=road[edge[i].to]) edge[i].len=edge[i^1].len=-1; zj=0; DFS(1,0); ans=ans-zj+1; } printf("%d\n",ans); return 0; }
自己的代码写炸了,不知为何..
时间: 2024-09-29 22:08:02