洛谷 P1041 传染病控制

传送门
老了啊……

一层一层搜
贪心可以得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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值