zoukankan      html  css  js  c++  java
  • [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 }
  • 相关阅读:
    Linux IO接口 监控 (iostat)
    linux 防火墙 命令
    _CommandPtr 添加参数 0xC0000005: Access violation writing location 0xcccccccc 错误
    Visual Studio自动关闭
    Linux vsftpd 安装 配置
    linux 挂载外部存储设备 (mount)
    myeclipse 9.0 激活 for win7 redhat mac 亲测
    英文操作系统 Myeclipse Console 乱码问题
    Linux 基本操作命令
    linux 查看系统相关 命令
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/7560921.html
Copyright © 2011-2022 走看看