• [IOI 2011]Race


    Description

    给一棵树,每条边有非负权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, 1 <= K <= 1000000

    Input

    第一行 两个整数 n, k

    第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始)

    Output

    一个整数 表示最小边数量 如果不存在这样的路径 输出-1

    Sample Input

    4 3

    0 1 1

    1 2 2

    1 3 4

    Sample Output

    2

    题解

    做了一上午的狗屎题,其实很水(点分裸题)...老是找不出细节错误....

    • 在每一棵点分治的树中只考虑经过根的路径;
      • (1)某一点到根的路径
        • 只需要算出每个点到根的距离即可判断。
      • (2)来自根节点不同儿子所在子树的两个点构成的路径
        • 每个点相当于有三个参数$belong[i]$,$dis[i]$,$s[i]$,分别表示删除根后属于哪个联通快,到根的路径长度以及路径上的边数;
        • 原问题相当于求$min(s[i]+s[j])$,$belong[i]!=belong[j]$,$dis[i]+dis[j]=k$。
    • 依次处理根的每一棵子树;
    • $f[i]$表示已经处理过的子树中到根距离为$i$的点中$s$值最小为多少;
    • 当处理下一棵子树时,每个点所能匹配的点到根的距离都是固定的,直接拿出对应的$f$值更新答案即可,然后利用这棵子树更新$f$数组;
    • 这样保证了更新答案的两点$belong$值不同,$dis$相加等于$k$,同时直接找出当前最优解。
    • 易发现,所有路径都是在这个方法中考虑过的,显然是可行的。
      1 //It is made by Awson on 2017.9.20
      2 #include <set>
      3 #include <map>
      4 #include <cmath>
      5 #include <ctime> 
      6 #include <queue>
      7 #include <stack>
      8 #include <string>
      9 #include <cstdio>
     10 #include <vector>
     11 #include <cstdlib>
     12 #include <cstring>
     13 #include <iostream>
     14 #include <algorithm>
     15 #define Min(a, b) ((a) < (b) ? (a) : (b))
     16 #define Max(a, b) ((a) > (b) ? (a) : (b))
     17 #define LL long long
     18 using namespace std;
     19 const int N = 200000;
     20 const int K = 1000000;
     21 const int INF = ~0u>>1;
     22 
     23 inline int Read() {
     24     int sum = 0;
     25     char ch = getchar();
     26     while (ch < '0' || ch > '9') ch = getchar();
     27     while (ch >= '0' && ch <= '9') sum = (sum<<1) + (sum<<3) + ch - 48, ch = getchar();
     28     return sum;
     29 }
     30 int n, k, u, v, c;
     31 struct tt {
     32     int to, cost, next;
     33 }edge[N*2+5];
     34 int path[N+5], top;
     35 int ans = INF;
     36 int size[N+5], mxsize[N+5];
     37 bool vis[N+5];
     38 int minsize, root;
     39 int f[K+5];
     40 
     41 inline void add(int u, int v, int c) {
     42     edge[++top].to = v;
     43     edge[top].cost = c;
     44     edge[top].next = path[u];
     45     path[u] = top;
     46 }
     47 void dfs_size(int u, int fa) {
     48     size[u] = 1;
     49     mxsize[u] = 0;
     50     for (int i = path[u]; i; i = edge[i].next)
     51         if ((!vis[edge[i].to]) && edge[i].to != fa) {
     52             dfs_size(edge[i].to, u);
     53             size[u] += size[edge[i].to];
     54             mxsize[u] = Max(mxsize[u], size[edge[i].to]);
     55         }
     56 }
     57 void dfs_getroot(int r, int u, int fa) {
     58     mxsize[u] = Max(mxsize[u], size[r]-size[u]);
     59     if (mxsize[u] < minsize) minsize = mxsize[u], root = u;
     60     for (int i = path[u]; i; i = edge[i].next)
     61         if ((!vis[edge[i].to]) && edge[i].to != fa)
     62             dfs_getroot(r, edge[i].to, u);
     63 }
     64 void dfs_getans(int u, int fa, int cnt, int val) {
     65     if (val > k) return;
     66     if (val == k) {
     67         ans = Min(ans, cnt);
     68         return;
     69     }
     70     int tmp = k-val;
     71     if (f[tmp]) ans = Min(f[tmp]+cnt, ans);
     72     for (int i = path[u]; i; i = edge[i].next)
     73         if ((!vis[edge[i].to]) && edge[i].to != fa)
     74             dfs_getans(edge[i].to, u, cnt+1, val+edge[i].cost);
     75 }
     76 void dfs_update(int u, int fa, int cnt, int val) {
     77     if (val >= k) return;
     78     if (!f[val]) f[val] = cnt;
     79     else f[val] = Min(f[val], cnt);
     80     for (int i = path[u]; i; i = edge[i].next)
     81         if ((!vis[edge[i].to]) && edge[i].to != fa)
     82             dfs_update(edge[i].to, u, cnt+1, val+edge[i].cost);
     83 }
     84 void dfs_delete(int u, int fa, int val) {
     85     if (val >= k) return;
     86     f[val] = 0;
     87     for (int i = path[u]; i; i = edge[i].next)
     88         if ((!vis[edge[i].to]) && edge[i].to != fa)
     89             dfs_delete(edge[i].to, u, val+edge[i].cost);
     90 }
     91 void solve(int x) {
     92     minsize = INF;
     93     dfs_size(x, 0);
     94     dfs_getroot(x, x, 0);
     95     vis[root] = true;
     96     for (int i = path[root]; i; i = edge[i].next)
     97         if (!vis[edge[i].to]) {
     98             dfs_getans(edge[i].to, root, 1, edge[i].cost);
     99             dfs_update(edge[i].to, root, 1, edge[i].cost);
    100         }
    101     for (int i = path[root]; i; i = edge[i].next)
    102         if (!vis[edge[i].to])
    103             dfs_delete(edge[i].to, root, edge[i].cost);
    104     for (int i = path[root]; i; i = edge[i].next)
    105         if (!vis[edge[i].to])
    106             solve(edge[i].to);
    107 }
    108 void work() {
    109     for (int i = 1; i < n; i++) {
    110         u = Read(); v = Read(); c = Read();
    111         u++, v++;
    112         add(u, v, c);
    113         add(v, u, c);
    114     }
    115     ans = INF;
    116     solve(1);
    117     printf("%d
    ", ans == INF ? -1 : ans);
    118 }
    119 int main() {
    120     int size = 128 << 20;                      //==========//
    121     char *p = (char*)malloc(size) + size;      //手 动 扩 栈//
    122     __asm__("movl %0, %%esp
    " :: "r"(p));     //==========//
    123     n = Read(); k = Read();
    124     work();return 0;
    125 }
  • 相关阅读:
    java架构师学习目录 sany
    python学习字符串 sany
    python中os.open()和open()区别 sany
    python3学习列表 sany
    C语言博客园作业03
    c语言博客作业02
    程序员竞争力列表
    《程序员》三月刊摘要
    Storage Systems IMPACT 课程结束
    deployJava.js的一个缺憾:无法正确检测客户端JRE
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/7560921.html
Copyright © 2020-2023  润新知