상세 트 리 DP
N 개의 노드 가 있 는 트 리 를 지정 합 니 다.(일반적으로 뿌리 가 없 는 트 리 이면 N-1 개의 방향 이 없 음)노드 를 루트 노드 로 선택 할 수 있 습 니 다.
일반적으로 노드 가 깊이 에서 얕 은(서브 트 리 가 작은 것 에서 큰 것 까지)순서 로 dp 단계 순서 로 한다.
dp 의 상태 표시 에서 첫 번 째 는 노드 번호(노드 번 호 는 이 노드 를 뿌리 로 하 는 서브 트 리 를 대표 합 니 다)
각 노드 x 에 대해 먼저 그의 모든 하위 노드 에 걸 쳐 dp 를 하고 거 슬러 올 라 갈 때 하위 노드 에서 x 로 상태 이동 을 한다.
A - Anniversary part
N 명의 직원,번 호 는 1~N 입 니 다.
그들 사이 에는 종속 관계 가 있다.즉,그들의 관 계 는 마치 교장 을 뿌리 로 하 는 나무 와 같 고,아버지의 결점 은 바로 자식 결점 의 직속 상사 이다.지금 연회 가 있 습 니 다.연회 에 직원 을 초대 할 때마다 i 는 일정한 즐거움 지 수 를 증가 시 킵 니 다.그러나 어떤 직원 의 직속 상사 가 오 면 이 직원 은 오지 않 습 니 다.어떤 직원 을 초대 하면 즐거움 지수 가 가장 크 고 수출 이 가장 큰 즐거움 지 수 를 계산 할 수 있 습 니까?
dp[x][0]을 설정 하면 x 를 뿌리 로 하 는 서브 트 리 에서 일부 직원 을 초대 하고 x 가 참가 하지 않 을 때 즐거움 지수 총계 의 최대 치 를 나타 낸다.이때 x 서브 노드(직접 부하)는 참가 할 수도 있 고 참가 하지 않 을 수도 있다(s 는 x 서브 노드 를 나타 낸다).
dp[x][1]을 설정 하면 x 를 뿌리 로 하 는 서브 트 리 에서 일부 직원 을 초대 하고 x 가 참가 할 때 쾌락 지수 총계 의 최대 치 를 나타 낸다.이때 x 서브 노드(직접 부하)는 참가 할 수 없다.H[x]는 현재 노드(x)의 쾌락 지수(s 는 x 서브 노드 를 나타 낸다)를 나타 낸다.
이 문 제 는 뿌리 가 있 는 나 무 를 주면 뿌리 노드 부터 시작 할 수 있 습 니 다.dp 목 표 는 max(F[root,0],F[root,1])시간 복잡 도 ON 입 니 다.
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> son[10010];
int dp[10010][2];//0 ,1
int v[10010];//
int h[10010];//
int n;
void DFS(int x){
dp[x][0] = 0;
dp[x][1] = h[x];
for (int i = 0; i < son[x].size(); i++)
{
int y = son[x][i];
DP(y);
dp[x][0] += max(dp[y][0],dp[y][1]);
dp[x][1] += dp[y][0];
}
}
int main(){
cin>>n;
for (int i = 1; i <=n ; i++)
scanf("%d",&h[i]);
for (int i = 1; i <n ; i++)
{
int x,y;
cin>>x>>y;
v[x] = 1;//x
son[y].push_back(x);//x y
}
int root;
for (int i = 1; i <= n; i++)
if(!v[i]){ //i
root = i;
break;
}
DFS(root);
cout << max(dp[root][0],dp[root][1]) << endl;
return 0;
}
B - Strategic gamen 개의 점 이 있 습 니 다.어떤 점 에 보초병 을 배치 하고 모든 보초병 은 그것 과 연 결 된 점 을 감시 할 수 있 습 니 다.모든 점 을 감시 하 는 데 필요 한 최소 보초병 수 를 물 어 볼 수 있 습 니 다.
즉,n 개의 결점 이 있 는 나 무 는 그 중의 정점 을 선택 하여 트 리 의 모든 변(u,v),u 와 v 가 적어도 하 나 를 선택 할 수 있 도록 해 야 한다.선택 한 정점 이 가장 적은 방안 을 제시 해 야 한다.
dp[x][0]을 설정 하면 노드 x 를 선택 하지 않 은 상태 에서 x 를 뿌리 노드 로 하 는 서브 트 리 로 최소 선택 할 노드 수 를 표시 합 니 다.
i 가 잎 노드 일 때
i 가 잎 노드 가 아 닐 때(s 는 x 자 노드 를 표시 합 니 다)
dp[x][1]을 설정 하면 노드 x 를 선택 한 상황 에서 x 를 루트 노드 로 하 는 서브 트 리 로 최소 선택 할 노드 수 를 표시 합 니 다.
i 가 잎 노드 일 때
i 가 잎 노드 가 아 닐 때(s 는 x 자 노드 를 표시 합 니 다)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#define maxn 1508
using namespace std;
int dp[maxn][2];
int soncnt[maxn];
int parent[maxn];
int n;
void DFS(int x) {
int i, d1=0, d0=0;
if (soncnt[x] == 0) {
dp[x][0] = 0;
dp[x][1] = 1;
return;
}
for (i=0; i < n; i++) {
if (parent[i] == x) {
DFS(i);
d1 += min(dp[i][0], dp[i][1]);
d0 += dp[i][1];
}
}
dp[x][1] = d1 + 1;
dp[x][0] = d0;
}
int main() {
int dad, son, m;
while (cin >> n) {
memset(soncnt, 0, sizeof(soncnt));
memset(parent, -1, sizeof(parent));
int root = -1;
for (int i = 0; i < n; i++) {
scanf("%d:(%d)", &dad, &m);
soncnt[dad] = m;
if (root == -1) {
root = dad;
}
while (m--) {
scanf("%d", &son);
parent[son] = dad;
}
}
DFS(root);
cout << min(dp[root][0], dp[root][1]) << endl;
}
return 0;
}
C - Tree Cuttingn 개의 결점 을 가 진 나 무 를 주 고 노드 번 호 는 1~n 이다.
―어떤 결점 을 삭제 한 후 나머지 키 트 리 의 크기 는 원 총 점 의 절반 보다 작 습 니까?
한 노드 를 철거 한 후에 나머지 부분 은 몇 명의 아들 의 나무 와 이 노드 상층 부 에 연 결 된 나머지 부분(n-size[i])이다.이런 연결 블록 의 크기 가 n/2 를 초과 하지 않 으 면 이 노드 는 조건 을 만족 시 킬 수 있다.따라서 우 리 는 먼저 각 노드 가 관할 하 는 그 나무의 크기 를 구하 고 아래 에서 위로 모든 노드 에 그 나무 규모(이 점 규모=그 아들 의 규모 와+1)를 구 할 수 있다.
나 무 를 만 들 때 직접 연결 표(vector)로 무 방향 변 을 저장 할 수 있 습 니 다.이 때 각 점 과 연 결 된 것 이 아버지 노드 인지 자식 노드 인지 구분 할 수 없 기 때문에 문 제 를 일 으 킬 수 있 습 니 다.dfs 때 아버지 노드 를 아들 노드 로 오인 하고 해결 방법 은 재 귀 할 때 아버지 노드 번호 에 들 어간 다음 에 재 귀 하고 규 모 를 계산 하 는 것 입 니 다.크기 를 비교 할 때 는 피해 주시 면 됩 니 다.
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<algorithm>
using namespace std;
int n;
int root;
vector<int>G[10000+400];
vector<int>ans;
int sz[10000+400];
void dfs(int par,int u){
sz[u]=1;
for(int i=0;i<(int)G[u].size();i++){
if(G[u][i]!=par)
dfs(u,G[u][i]);
}
int piece=0;
for(int i=0;i<(int)G[u].size();i++)
if(par!=G[u][i]){
sz[u]+=sz[G[u][i]];
piece=max(piece,sz[G[u][i]]);
}
piece=max(piece,n-sz[u]);
if(piece<=n/2)
ans.push_back(u);
}
int main(){
while(cin>>n){
memset(sz,0,sizeof(sz));
int x,y;
for(int i=0;i<n-1;i++){
scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
dfs(0,1);
sort(ans.begin(),ans.end());
for(int i=0;i<(int)ans.size();i++)
cout<<ans[i]<<endl;
}
return 0;
}
LCA 최근 공공 조상배가(2 점 에 기초 한 방법)
만약 에 나무의 두 점 이 같은 깊이 에 있 을 때 위로 mid 걸음 을 뛰 는 것 은 단조 로 운 것 이 분명 하 다.
만약 그들 이 위로 뛰 어 오 르 는 mid 걸음 이 같은 점 이 라면,이 점 은 그들의 공동 조상 이지 만,반드시 최근 의 공공 조상 은 아니다.
그러면 만약 에 우리 가 모든 점 에서 위로 몇 걸음 뛰 는 것 이 누구 인지 빨리 얻 을 수 있다 면 분명히 우 리 는 2 점 을 이용 하여 LCA 를 구 할 수 있다.
이것 은 배로 늘 려 서 할 수 있다.
배가 되 는 사상 은 사실 매우 간단 하 다.바로 이 진 사상 을 이용 하 는 것 이다.명확 한 결론 은 다음 과 같다.
노드 u 위로 뛰 기 2^(k+1)천의 조상=(노드 u 위로 뛰 기 2k 천의 조상)위로 뛰 기 2k 천의 조상
코드 로 표시 하면:
fa[u][k + 1] = fa[ fa[u][k] ][k];
이것 의 예비 처리 도 매우 간단 하 다.우 리 는 모든 fa[u][0]을 초기 화하 면 된다.왜냐하면 다음 부분 은 위의 공식 에 따라 전달 할 수 있 기 때문이다.그리고 이것 을 미리 처리 한 후에 우 리 는 이것 에 따라 2 분 을 진행 할 수 있 습 니 다.코드 는 다음 과 같 습 니 다.
int fa[maxn][20], dep[maxn];
void dfs(int u, int f, int d)
{
dep[u] = d;
fa[u][0] = f;
for(int i = 1; i < 20; ++i)
{
fa[u][i] = fa[fa[u][i - 1]][i] - 1;
}
for(int i = head[u]; ~i; i = nxt[i])
{
int t = to[i];
if(t != f)
{
dfs(t, u, d + 1);
}
}
}
int lca(int u, int v)
{
if(dep[u] < dep[v]) swap(u, v);
int k = dep[u] - dep[v];
for(int i = 0; i < k; ++i)
{
if((1 << i) & k) u = fa[u][i];
}
if(u == v) return u;
for(int i = 19; i >= 0; --i)
{
if(fa[u][i] != fa[v][i])
{
u = fa[u][i];
v = fa[v][i];
}
}
return fa[u][0];
}
이상 은 트 리 DP 에 대한 상세 한 내용 입 니 다.트 리 DP 에 관 한 자 료 는 저희 의 다른 관련 글 을 주목 해 주 십시오!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
물체 검출의 평가 지표 IoU의 계산 방법Yolo나 SSD 등 물체 검출에서 평가 지표로 사용되는 IoU에 대해 조사했으므로 정리했습니다. IoU (Intersection over Union)는 두 영역이 얼마나 겹치는지를 나타내는 지표입니다. 두 영역의 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.