20200722T1 【NOIP2015模拟10.29A组】三色树 Description Input Output Sample Input Sample Output Data Constraint solution code

给出一个N个节点的无根树,每条边有非负边权,每个节点有三种颜色:黑,白,灰。
一个合法的无根树满足:树中不含有黑色结点或者含有至多一个白色节点。
现在希望你通过割掉几条树边,使得形成的若干树合法,并最小化割去树边权值的和。

Input

第一行一个正整数N,表示树的节点个数。
第二行N个整数Ai,表示i号节点的颜色,0 表示黑色,1表示白色,2表示灰色。
接下来N-1行每行三个整数Xi Yi Zi,表示一条连接Xi和Yi权为Zi的边。

Output

输出一个整数表示其最小代价。

Sample Input

  5 
  0 1 1 1 0
  1 2 5
  1 3 3
  5 2 5
  2 4 16

Sample Output

10
样例解释:
花费10的代价删去边(1, 2)和边(2, 5)。

Data Constraint

20%的数据满足N≤10。
另外30%的数据满足N≤100,000,且保证树是一条链。
100%的数据满足N≤300,000,0≤Zi≤1,000,000,000,Ai∈{0,1,2}。

solution

一眼显然树形DP

仔细思考发现不好转移

还是暴力适合我

void add(int x,int y,int z)
{
    ver[++cut] = y; next[cut] = head[x]; head[x] = cut; w[cut] = z;
}
int lowbit(int x)
{
    return x&-x;
}
int count(int x)
{
    int num = 0;
    for(; !(x&1); x >>= 1)num ++;
    return ++num ;
}
void dfs(int x,int fa)
{
    book[x] = 1;
    if(color[x] == 1) white++;
    else if(color[x] == 0) black++;
    for(R int i = head[x]; i; i = next[i])
    {
        int y = ver[i], z = w[i];
        if(y == fa)continue;
        dfs(y,x);
    }
}
bool check()
{
    for(R int i = 1; i <= n; i++)
    {
        if(!book[i])
        {
            black = 0; white = 0;
            dfs(i,0);
            if(black && white > 1)return false;
        }
    }
    return true;
}
signed main()
{
    read(n);
    for(R int i = 1; i <= n; i++) read(color[i]);
    if(n<=10)
    {
        for(R int i = 1; i < n; i++) read(a[i]), read(b[i]), read(c[i]), SUM += c[i];
        for(R int i = 0; i <= (1<<(n-1))-1; i++)
        {
            int now = i, sum = 0;
            cut = 0; memset(head,0,sizeof(head)); 
            while(now)
            {
                int which = count(now );
                add(a[which],b[which],c[which]);
                sum += c[which];
                now -= lowbit(now);
            }
            memset(book,0,sizeof(book));
            if(check()) ans = min(ans,SUM - sum );
        }
        writeln(ans);
        return 0;
    }
    writeln(0);
    return 0;
}

问链就是打挂了

正解貌似从下往上扫

dp[i][0 / 1 / 2]  在i节点,0表示没有黑色,1表示没有白色,2表示有一个白色

先挖坑

——————————————————————————————————————————分割线

copy了zjy的

不过没有弄人工栈只有70points

zjy题解

人工栈。。。再挖个坑

code

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<queue>
 7 #include<vector>
 8 #include<stack>
 9 #include<set>
10 #include<deque>
11 #include<map>
12 using namespace std;
13 
14 template <typename T> void read(T &x) {
15     x = 0; int f = 1; char c;
16     for (c = getchar(); c < '0' || c > '9'; c = getchar()) if (c == '-') f = -f;
17     for (; c >= '0' && c <= '9'; c = getchar()) x = 10 * x + c - '0' ;
18     x *= f;
19 }
20 template <typename T> void write(T x){
21     if (x < 0) putchar('-'), x = -x;
22     if (x > 9) write(x / 10);
23     putchar(x % 10 + '0');
24 }
25 template <typename T> void writeln(T x) { write(x); putchar('
'); }
26 template <typename T> void writesn(T x) { write(x); putchar(' '); }
27 
28 #define int long long
29 #define inf 123456789012345678
30 #define next net
31 #define P 1000000007
32 #define N 600020
33 #define mid ((l+r)>>1)
34 #define lson (o<<1)
35 #define rson (o<<1|1)
36 #define R register
37 
38 int n,cut;
39 int color[N ];
40 int next[N ],head[N ],ver[N ],w [N ];
41 int f[N ][3],book[N ];
42 inline void add(int x,int y,int z)
43 {
44     ver[++cut] = y; next[cut] = head[x]; head[x] = cut; w[cut] = z;
45 }
46 inline void dfs(int x)
47 {
48     book[x] = 1;
49     if(color[x] == 0) f[x][0] = inf;
50     else if(color[x] == 1) f[x][1] = inf;
51     int maxx = 0;
52     for(R int i = head[x]; i; i = next[i])
53     {
54         int y = ver[i], z = w[i];
55         if(book[y]) continue;
56         dfs(y);
57         if(color[x] == 0)
58         {
59             f[x][1] += min(f[y][1], min(f[y][0], f[y][2]) + z);
60             maxx = max(maxx, min(f[y][1], min(f[y][0], f[y][2]) + z) - f[y][2]);
61         }
62         else if(color[x] == 1)
63         {
64             f[x][0] += min(f[y][0], min(f[y][1], f[y][2]) + z);
65             f[x][2] += min(f[y][1], min(f[y][0], f[y][2]) + z);
66         }
67         else
68         {
69             f[x][0] += min(f[y][0], min(f[y][1], f[y][2]) + z);
70             f[x][1] += min(f[y][1], min(f[y][0], f[y][2]) + z);
71             maxx = max(maxx, min(f[y][1], min(f[y][0], f[y][2]) + z) - f[y][2]);
72         }
73     }
74     if(color[x] != 1) f[x][2] = f[x][1] - maxx;
75 }
76 signed main()
77 {
78     //freopen("tree2.in","r",stdin);
79     //freopen("tree2.out","w",stdout);
80     read(n);
81     for(R int i = 1; i <= n; i++) read(color[i]);
82     for(R int i = 1, x, y, z; i < n; i++)
83     {
84         read(x); read(y); read(z);
85         add(x, y, z); add(y, x, z);
86     }
87     dfs(1);
88     writeln(min(f[1][0], min(f[1][1], f[1][2])));
89     return 0;
90 }