1. 程式人生 > >【AtCoder1981】Shorten Diameter(圖論思維)

【AtCoder1981】Shorten Diameter(圖論思維)

題意

給一棵樹,要求刪去最少的點,使得樹聯通且直徑小於等於K (N<=2000)

題解

簡單的問題也容易想複雜。

對於K為偶數,列舉一個點,將距離此點>K/2的全部刪掉即可滿足條件,取刪點數最小值。 對於K為奇數,列舉一條邊,樹被此邊分為兩棵,將其深度>(K-1)/2的全部刪掉,取刪點數最小值。

考試時想複雜了:把直徑求出,然後試圖從直徑兩頭刪點,包含大量特殊情況。。。死路一條

程式碼

#include<cstdio>
#include<vector>
using namespace std;
const int MAXN=2005;

int N,K;
vector<
int> adj[MAXN]; int dep[MAXN],fa[MAXN],cnt; void dfs(int u,int f,int lim) { for(int i=0;i<(int)adj[u].size();i++) { int v=adj[u][i]; if(v!=f) { dep[v]=dep[u]+1; if(dep[v]>lim) cnt++; dfs(v,u,lim); } }
} int main() { scanf("%d%d",&N,&K); for(int i=1;i<N;i++) { int u,v; scanf("%d%d",&u,&v); adj[u].push_back(v); adj[v].push_back(u); } int ans=0x3F3F3F3F; if(K%2==0) { for(int i=1;i<=N;i++) { cnt=
0; dep[i]=0;dfs(i,0,K/2); ans=min(ans,cnt); } } else { for(int i=1;i<=N;i++) for(int j=0;j<(int)adj[i].size();j++) { cnt=0; dep[i]=0;dfs(i,adj[i][j],K/2); dep[adj[i][j]]=0;dfs(adj[i][j],i,K/2); ans=min(ans,cnt); } } printf("%d\n",ans); return 0; }