传送门
老了啊……
一层一层搜
贪心可以得90分,即优先切子结点多的,如果子结点数量相同,就切连边多的。但是反例也很好找,所以爆搜最稳妥了。最下面是没过的数据。
复杂度为每层结点数相乘;
剪枝很基础;
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=10001;
int n,m,tot,dep,ans=2147483647,wu;
int fst[MAXN],nxt[MAXN],fa[MAXN],son[MAXN],deep[MAXN];
int h[1001][1001];
bool vis[MAXN];
struct hh
{
int f,t;
}ma[MAXN<<1];
void build(int f,int t)
{
ma[++tot]=(hh){f,t};
nxt[tot]=fst[f];
fst[f]=tot;
return;
}
void dfs(int x,int f)
{
fa[x]=f;
deep[x]=deep[f]+1;
son[x]++;
for(int i=fst[x];i;i=nxt[i])
{
int u=ma[i].t;
if(u==f) continue;
dfs(u,x);
son[x]+=son[u];
}
return;
}
void cut(int x,int f)
{
vis[x]=f;
for(int i=fst[x];i;i=nxt[i])
{
int u=ma[i].t;
if(u!=fa[x])
cut(u,f);
}
return;
}
void calc(int geli,int depth,int ganran)
{
if(geli+ganran==n || depth>dep || ganran>=ans)
{
ans=min(ans,ganran);
return;
}
int cnt=0;
for(int i=1;i<=h[depth][0];i++)
if(vis[h[depth][i]]) cnt++;
for(int i=1;i<=h[depth][0];i++)
{
int x=h[depth][i];
if(vis[x]) continue;
cut(x,1);
calc(geli+son[x],depth+1,ganran+h[depth][0]-cnt-1);
cut(x,0);
}
return;
}
void solve()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
build(x,y),build(y,x);
}
dfs(1,1);
for(int i=1;i<=n;i++)
{
h[deep[i]][++h[deep[i]][0]]=i;
dep=max(dep,deep[i]);
}
calc(0,2,1);
cout<<ans<<endl;
return;
}
int main()
{
solve();
return 0;
}
100 99
2 1
3 2
4 3
5 3
6 3
7 2
8 7
9 7
10 9
11 7
12 2
13 12
14 12
15 12
16 2
17 16
18 17
19 17
20 16
21 2
22 21
23 21
24 21
25 1
26 25
27 26
28 25
29 28
30 25
31 30
32 31
33 31
34 31
35 30
36 35
37 35
38 37
39 37
40 1
41 40
42 41
43 41
44 41
45 41
46 40
47 46
48 40
49 40
50 49
51 40
52 51
53 51
54 40
55 54
56 54
57 1
58 57
59 58
60 58
61 58
62 57
63 62
64 62
65 62
66 57
67 66
68 66
69 66
70 66
71 57
72 71
73 71
74 71
75 74
76 57
77 76
78 76
79 76
80 76
81 1
82 81
83 82
84 83
85 82
86 85
87 81
88 87
89 88
90 88
91 87
92 87
93 92
94 92
95 94
96 92
97 96
98 96
99 92
100 99