1. 程式人生 > 實用技巧 >洛谷 P1041 傳染病控制 題解

洛谷 P1041 傳染病控制 題解

這道題是一個錯題,但是我還是做了。

一開始我想的是一個貪心的做法,但是如果樹含有一條很長的鏈就會hack掉這種做法,而資料範圍並不大,所以就老老實實地寫搜尋。

大體上是先搜尋一遍整棵樹,處理處每個點的父親節點編號,子樹大小和所在深度。

然後需要把相同深度的點歸到一起,因為對於每次搜尋,可選擇的都是同一層的點(本來是邊,可以轉換成點)。

然後就是根據題意搜尋:每次在同層的點中選一個切斷。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include
<vector> #define maxn 610 #define int long long #define rep(i,s,e) for(register int i=s;i<=e;++i) #define dwn(i,s,e) for(register int i=s;i>=e;--i) using namespace std; inline int read() { int x=0,f=1; char c=getchar(); while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();}
while(c>='0'&&c<='9') {x=x*10+c-'0'; c=getchar();} return f*x; } inline void write(int x) { if(x<0){putchar('-');x=-x;} if(x>9)write(x/10); putchar(x%10+'0'); } vector<int> sd[maxn]; int n,p,cnt,ans,maxdep; int head[maxn]; int fa[maxn],siz[maxn],deep[maxn],tag[maxn];
struct node { int v,nex; }edge[maxn]; inline void add(int x,int y) { edge[++cnt].v=y; edge[cnt].nex=head[x]; head[x]=cnt; } void pre_dfs(int now,int from,int dep) { fa[now]=from; siz[now]=1; deep[now]=dep; maxdep=max(maxdep,dep); for(int i=head[now];i;i=edge[i].nex) { int to=edge[i].v; if(to==from) continue; pre_dfs(to,now,dep+1); siz[now]+=siz[to]; } } void dfs(int dep,int f) { if(dep==maxdep+1) { ans=min(ans,f); return; } for(int i=0;i<sd[dep].size();++i) { if(tag[fa[sd[dep][i]]]==1) tag[sd[dep][i]]=1; else tag[sd[dep][i]]=0; } bool flag=0; for(int i=0;i<sd[dep].size();++i) { if(tag[sd[dep][i]]==0) flag=1; } if(flag==0) { ans=min(ans,f); return; } for(int i=0;i<sd[dep].size();++i) { if(tag[sd[dep][i]]==1) continue; tag[sd[dep][i]]=1; dfs(dep+1,f-siz[sd[dep][i]]); tag[sd[dep][i]]=0; } } signed main() { n=read();p=read(); ans=n; rep(i,1,p) { int x=read(),y=read(); add(x,y); add(y,x); } pre_dfs(1,0,1); rep(i,1,n) sd[deep[i]].push_back(i); dfs(2,n); write(ans); return 0; }