【AtCoder1981】Shorten Diameter(圖論思維)
阿新 • • 發佈:2018-12-11
題意
給一棵樹,要求刪去最少的點,使得樹聯通且直徑小於等於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;
}