Codeforces 1244D. Paint the Tree

传送门

首先如果某个点的度数大于 $2$ 那么显然无解

然后考虑点的度数小于等于 $2$ 的情况

发现其实是一条链

一旦确定了链开头的两个点,后面的点的颜色都可以通过之前的点推出

所以直接枚举即可

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=1e5+7;
const ll INF=1e18;
int fir[N],from[N<<1],to[N<<1],cntt;
inline void add(int a,int b) { from[++cntt]=fir[a]; fir[a]=cntt; to[cntt]=b; }
int n,cst[N][3],ans[3][3],col[N],pcol[N],du[N];
vector <int> V;
int main()
{
    n=read();
    for(int i=0;i<3;i++)
        for(int j=1;j<=n;j++) cst[j][i]=read();
    for(int i=1;i<n;i++)
    {
        int a=read(),b=read();
        add(a,b); add(b,a);
        du[a]++; du[b]++;
    }
    for(int i=1;i<=n;i++)
        if(du[i]>2) { printf("-1\n"); return 0; }
    int rt=0; for(int i=1;i<=n;i++) if(du[i]==1) { rt=i; break; }
    int pre=rt,now=to[fir[rt]]; V.push_back(rt);
    while(du[now]>1)
        for(int i=fir[now];i;i=from[i])
        {
            int &v=to[i]; if(v==pre) continue;
            V.push_back(now); pre=now; now=v; break;
        }
    V.push_back(now);
    ll ans=INF;
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++) if(i!=j)
        {
            int len=V.size(); ll res=cst[V[0]][i]+cst[V[1]][j];
            pcol[V[0]]=i; pcol[V[1]]=j;
            for(int k=2;k<len;k++)
            {
                for(int c=0;c<3;c++)
                    if(c!=pcol[V[k-1]]&&c!=pcol[V[k-2]]) pcol[V[k]]=c;
                res+=cst[V[k]][pcol[V[k]]];
            }
            if(res<ans)
                for(int k=0;k<len;k++) col[V[k]]=pcol[V[k]];
            ans=min(ans,res);
        }
    printf("%lld\n",ans);
    for(int i=1;i<=n;i++) printf("%d ",col[i]+1);
    puts(""); return 0;
}

猜你喜欢

转载自www.cnblogs.com/LLTYYC/p/11669434.html
今日推荐