这一题,枚举根节点。
先贴上两个性质:
定义Dp[u]表示以u为根结点,保证u的子树中所有节点都能被区分的最少信号塔数量。
因为son已经保证了其子树能被区分,所以只考虑u的直系子节点能否被区分。
如果有两个及以上的子节点,那么它们是不能被区分的,所以需要在u处放一个信号塔,从结论一得。
Code:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int Maxn = 5000;
const int Maxm = 5000;
struct node{
int v, nxt;
}edge[(Maxm << 1) + 5];
int N, cnt;
int Dp[Maxn + 5], fir[Maxn + 5];
char S[Maxn + 5];
bool getint(int & num){
char c; int flg = 1; num = 0;
while((c = getchar()) < '0' || c > '9'){
if(c == '-') flg = -1;
if(c == -1) return 0;
}
while(c >= '0' && c <= '9'){
num = num * 10 + c - 48;
if((c = getchar()) == -1) return 0;
}
num *= flg;
return 1;
}
void addedge(int a, int b){
edge[++ cnt].v = b, edge[cnt].nxt = fir[a], fir[a] = cnt;
}
void Get_Dp(int u, int fa){
Dp[u] = 0;
int tot = 0;
for(int i = fir[u]; i; i = edge[i].nxt) if(edge[i].v != fa){
int v = edge[i].v;
Get_Dp(v, u);
if(! Dp[v]) ++ tot;
else Dp[u] += Dp[v];
}
if(tot) Dp[u] += tot - 1;
}
int main(){
//freopen("tps.in", "r", stdin);
//freopen("tps.out", "w", stdout);
getint(N);
for(int i = 1; i <= N; ++ i){
scanf("%s", S + 1);
for(int j = 1; j <= N; ++ j) if(S[j] == 'Y')
addedge(i, j);
}
int Ans = N;
for(int Root = 1; Root <= N; ++ Root){
Get_Dp(Root, 0);
Ans = min(Dp[Root] + 1, Ans);
}
printf("%d\n", Ans);
return 0;
}