BZOJ 3197 Sdoi 2013 assassin 동적 기획 + 트리 구성 + 비용 흐름
이 문제는 솜씨가 아주 뛰어나다--
우선 3162와 같은 처리 방식을 가지고 이 나무의 중심을 뿌리로 삼고 중심이 두 개면 한 뿌리를 새로 만들고 이 두 중심을 향해
f[x][y]는 x가 있는 하위 트리의 첫 번째 그룹 값과 y가 있는 하위 트리의 두 번째 그룹 값이 일치하는 최소 비용을 나타낸다
이동의 필수 조건은 x가 있는 하위 트리와 y가 있는 하위 트리가 같고 x와 y의 깊이가 같다는 것이다
후효성을 확보하기 위해서 x의 모든 하위 노드와 y의 모든 하위 노드 사이의 최소 비용은 반드시 이미 구해야 한다
그러면 우리는 노드를 깊이의 상반수로 첫 번째 키 값을,Hash값은 두 번째 키 값으로 정렬하여 왼쪽에서 오른쪽으로 열거하는 깊이가Hash와 같은 점으로 이동한다
이분도 최대권 완비 매칭
매번 x를 y로 옮길 때마다 우리는 x와 y로 구성된 자수 사이를 일일이 일치시켜야 한다. 그래서 우리는 이분도의 가장 큰 권한을 가진 완비 일치로 이 물건을 만들 수 있다.
KM을 모르는구나. QAQ. 그래서 비용 흐름을 썼어요. -
코드를 4.6KB로 썼는데 별로 안 맞춰서 1A가 됐어요. - 감동적이에요.
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 710
#define ORIGIN 233
#define BASE 233333333
#define S 0
#define T 29
#define INF 0x3f3f3f3f
using namespace std;
int n,f1[M],f2[M],f[M][M];
pair<pair<int,unsigned long long>,int> sorter[M];
// ,
namespace Trees_Isomorphism{
struct abcd{
int to,next;
}table[M<<1];
int head[M],tot=1;
int root,cg[2];
int fa[M],size[M],dpt[M];
unsigned long long hash[M];
void Add(int x,int y)
{
table[++tot].to=y;
table[tot].next=head[x];
head[x]=tot;
}
void Get_Centre_Of_Gravity(int x,int from)
{
int i,flag=1;
size[x]=1;
for(i=head[x];i;i=table[i].next)
if(table[i].to!=from)
{
Get_Centre_Of_Gravity(table[i].to,x);
size[x]+=size[table[i].to];
if(size[table[i].to]<<1>n)
flag=0;
}
if(n-size[x]<<1>n)
flag=0;
if(flag)
(cg[0]?cg[1]:cg[0])=x;
}
void Get_Hash(int x)
{
static int stack[M];
int i,top=0;
dpt[x]=dpt[fa[x]]+1;
for(i=head[x];i;i=table[i].next)
if(table[i].to!=fa[x])
{
fa[table[i].to]=x;
Get_Hash(table[i].to);
}
for(i=head[x];i;i=table[i].next)
if(table[i].to!=fa[x])
stack[++top]=hash[table[i].to];
sort(stack+1,stack+top+1);
hash[x]=ORIGIN;
for(i=1;i<=top;i++)
(((hash[x]*=BASE)^=stack[i])+=stack[i])^=stack[i];
}
}
namespace Min_Cost_Max_Flow{
struct abcd{
int to,flow,cost,next;
}table[10100];
int head[30],tot=1;
int ans;
void Initialize()
{
memset(head,0,sizeof head);
tot=1;ans=0;
}
void Add(int x,int y,int f,int c)
{
table[++tot].to=y;
table[tot].flow=f;
table[tot].cost=c;
table[tot].next=head[x];
head[x]=tot;
}
void Link(int x,int y,int f,int c)
{
Add(x,y,f,c);
Add(y,x,0,-c);
}
bool Edmonds_Karp()
{
static int q[65540],flow[30],cost[30],from[30];
static unsigned short r,h;
static bool v[M];
int i;
memset(cost,0x3f,sizeof cost);
flow[S]=INF;cost[S]=0;q[++r]=S;
while(r!=h)
{
int x=q[++h];v[x]=0;
for(i=head[x];i;i=table[i].next)
if(table[i].flow&&cost[table[i].to]>cost[x]+table[i].cost)
{
cost[table[i].to]=cost[x]+table[i].cost;
flow[table[i].to]=min(flow[x],table[i].flow);
from[table[i].to]=i;
if(!v[table[i].to])
v[table[i].to]=1,q[++r]=table[i].to;
}
}
if(cost[T]==INF) return false;
ans+=cost[T]*flow[T];
for(i=from[T];i;i=from[table[i^1].to])
table[i].flow-=flow[T],table[i^1].flow+=flow[T];
return true;
}
}
using namespace Trees_Isomorphism;
bool Compare(int x,int y)
{
return hash[x] < hash[y];
}
int DP(int x,int y)
{
static int stack1[M],stack2[M];
int i,j,k,l,top1=0,top2=0;
for(i=head[x];i;i=table[i].next)
if(table[i].to!=fa[x])
stack1[++top1]=table[i].to;
for(i=head[y];i;i=table[i].next)
if(table[i].to!=fa[y])
stack2[++top2]=table[i].to;
sort(stack1+1,stack1+top1+1,Compare);
sort(stack2+1,stack2+top2+1,Compare);
Min_Cost_Max_Flow::Initialize();
for(i=1;i<=top1;i=j)
{
for(j=i+1;j<=top1&&hash[stack1[i]]==hash[stack1[j]];j++);
for(k=i;k<j;k++)
for(l=i;l<j;l++)
Min_Cost_Max_Flow::Link(k,top1+l,1,f[stack1[k]][stack2[l]]);
}
for(i=1;i<=top1;i++)
{
Min_Cost_Max_Flow::Link(S,i,1,0);
Min_Cost_Max_Flow::Link(i+top1,T,1,0);
}
while( Min_Cost_Max_Flow::Edmonds_Karp() );
return Min_Cost_Max_Flow::ans+(f1[x]^f2[y]);
}
int main()
{
int i,j,x,y;
cin>>n;
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
Add(x,y);Add(y,x);
}
for(i=1;i<=n;i++)
scanf("%d",&f1[i]);
for(i=1;i<=n;i++)
scanf("%d",&f2[i]);
Get_Centre_Of_Gravity(1,0);
if(cg[1])
{
root=++n;
for(i=head[cg[0]];i;i=table[i].next)
if(table[i].to==cg[1])
{
table[i].to=table[i^1].to=n;
break;
}
Add(n,cg[0]);
Add(n,cg[1]);
}
else root=cg[0];
Get_Hash(root);
for(i=1;i<=n;i++)
sorter[i]=make_pair(make_pair(-dpt[i],hash[i]),i);
sort(sorter+1,sorter+n+1);
for(i=1;i<=n;i=j)
{
for(j=i+1;j<=n&&sorter[i].first==sorter[j].first;j++);
for(x=i;x<j;x++)
for(y=i;y<j;y++)
f[sorter[x].second][sorter[y].second]=DP(sorter[x].second,sorter[y].second);
}
cout<<f[root][root]<<endl;
return 0;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
01 가방, 완전 가방, 다중 가방 dp(동적 기획 입문 dp)01 가방은 2진법으로 직접 표시할 수 있지만 데이터 양이 너무 많으면 시간을 초과하는 것이 폭력이다.01 가방의 사상은 바로 이 물품에 대해 내가 넣은 가치가 큰지 안 넣은 가치가 큰지 비교하여 방정식 f[i][v...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.