zoukankan      html  css  js  c++  java
  • [IOI2007]训练路径

    Description

    马克(Mirko)和斯拉夫克(Slavko)正在为克罗地亚举办的每年一次的双人骑车马拉松赛而紧张训练。他们需要选择一条训练路径。 他们国家有N个城市和M条道路。每条道路连接两个城市。这些道路中恰好有N-1条是铺设好的道路,其余道路是未经铺设的土路。幸运的是,每两个城市之间都存在一条由铺设好的道路组成的通路。换句话说,这N个城市和N-1条铺设好的道路构成一个树状结构。 此外,每个城市最多是10条道路的端点。 一条训练路径由某个城市开始,途经一些道路后在原来起始的城市结束。因为马克和斯拉夫克喜欢去看新城市,所以他们制定了一条规则:绝不中途穿越已经去过的城市,并且绝不在相同的道路上骑行两次(不管方向是否相同)。训练路径可以从任何一个城市开始,并且不需要访问所有城市。 显然,坐在后座的骑行者更为轻松,因为坐在前面的可以为他挡风。为此,马克和斯拉夫克在每个城市都要调换位置。为了保证他们的训练强度相同,他们要选择一条具有偶数条道路的路径。 马克和斯拉夫克的竞争者决定在某些未经铺设的土路上设置路障,使得他们两人不可能找到满足上述要求的训练路径。已知在每条土路上设置路障都有一个费用值(一个正整数),并且竞争者不能在铺设好的道路上设置路障。 任务 给定城市和道路网的描述,写一个程序计算出为了使得满足上述要求的训练路径不存在,而需要的设置路障的最小总费用。

    Input

    输入的第一行包含两个整数N和M,(2≤N≤1000,N-1≤M≤5000),分别表示城市和道路的个数。 接下来的M行每行包含3个整数A, B和C(1≤A≤N, 1≤B≤N, 0≤C≤10 000), 用来描述一条道路。A和B是不同的整数,表示由这条道路直接相连的两个城市。对于铺设好的道路C是0;对于土路,c是在该条路上设置路障所需的费用值。 每个城市最多是10条道路的端点。任意两个城市都不会有多于一条直接相连的道路。

    Output

    输出包含一个整数,表示求出的最小总费用。

    Sample Input

    5 8
    2 1 0
    3 2 0
    4 3 0
    5 4 0
    1 3 2
    3 5 2
    2 4 5
    2 5 1

    Sample Output

    5

    HINT

    首先如果一条边的两个点在树上的路径长度为奇数,那么这条边肯定要删掉。

    那么我们可以发现,这时存在偶环的充要条件就是一个环经过了任意两条非树边。

    因为两个奇环通过公共边拼在一起,再把公共边挖掉,肯定是一个偶环。

    所以这道题的限制就是不能出现这种情况,也就是说我们需要留下一棵仙人掌。

    转化一下,改为求总边权减去最大留下的边权

    于是定义$f[i][S]$表示i点,不考虑S集合的儿子

    对于一个以i为LCA的非树边,如果都不留

    那么$f[i][S]=∑f[son][0]*[S不含son]$

    如果要选择边(u,v),那么u->i和v->i上不能与其他非树边形成的环有公共边

    答案由三部分组成:

    1.u和v的子树,无限制,取$f[u][0]$,$f[v][0]$

    2.u(或v)->i路径上求出每个点不考虑它到u(或v)的儿子的方案和

    $sum_{a=u}f[a][S]$

    S为不考虑该点到u(或v)

    3.i点不考虑到u的儿子son1,到v的儿子son2

    $f[i][S]$  S为没有考虑son1和son2的状态

    复杂度$O(m*2^{10}+m*n)$

    这里写图片描述

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<cmath>
      6 #include<vector>
      7 using namespace std;
      8 typedef long long lol;
      9 struct Edge
     10 {
     11   int u,v,d;
     12 }e[5001];
     13 struct Node
     14 {
     15   int next,to;
     16 }edge[10001];
     17 vector<int>h[1001];
     18 int f[1001][1301],son[1001],n,m,ans,LCA;
     19 int top[1001],head[1001],num,tot,dep[1001],dfn[1001],idf[1001],id[1001],fa[1001],size[1001];
     20 void add(int u,int v)
     21 {
     22   num++;
     23   edge[num].next=head[u];
     24   head[u]=num;
     25   edge[num].to=v;
     26 }
     27 void dfs1(int x,int pa)
     28 {int i;
     29   fa[x]=pa;
     30   size[x]=1;
     31   dep[x]=dep[pa]+1;
     32   for (i=head[x];i;i=edge[i].next)
     33     {
     34       int v=edge[i].to;
     35       if (v==pa) continue;
     36       dfs1(v,x);
     37       size[x]+=size[v];
     38       if (size[v]>size[son[x]]) son[x]=v;
     39     }
     40 }
     41 void dfs2(int x,int pa,int tp)
     42 {int i;
     43   top[x]=tp;
     44   if (son[x]) dfs2(son[x],x,tp);
     45   for (i=head[x];i;i=edge[i].next)
     46     {
     47       int v=edge[i].to;
     48       if (v==pa||v==son[x]) continue;
     49       dfs2(v,x,v);
     50     }
     51 }
     52 int get_lca(int x,int y)
     53 {
     54   while (top[x]!=top[y])
     55     {
     56       if (dep[top[x]]<dep[top[y]]) swap(x,y);
     57       x=fa[top[x]];
     58     }
     59   if (dep[x]<dep[y])
     60     return x;
     61   else return y;
     62 }
     63 void DP(int x,int pa)
     64 {int i,sum,j,p,u,v,cnt=0;
     65   for (i=head[x];i;i=edge[i].next)
     66     {
     67       int v=edge[i].to;
     68       if (v==pa) continue;
     69       DP(v,x);
     70     }
     71   cnt=0;
     72   for (i=head[x];i;i=edge[i].next)
     73     {
     74       int v=edge[i].to;
     75       if (v!=pa) id[cnt]=v,idf[v]=1<<cnt,cnt++;
     76     }
     77   for (i=0;i<=(1<<cnt)-1;i++)
     78     {sum=0;
     79       for (j=0;j<cnt;j++)
     80     if (!(i>>j&1))
     81       {
     82         sum+=f[id[j]][0];
     83       }
     84       f[x][i]=sum;
     85     }
     86   int ed=h[x].size();
     87   for (p=0;p<=ed-1;p++)
     88     {
     89       i=h[x][p];u=0;v=0;
     90       sum=e[i].d;
     91       if (e[i].u!=x)
     92     sum+=f[e[i].u][0];
     93       if (e[i].v!=x)
     94     sum+=f[e[i].v][0];
     95       if (e[i].u!=x)
     96       for (u=e[i].u;fa[u]!=x;u=fa[u])
     97     sum+=f[fa[u]][idf[u]];
     98       if (e[i].v!=x)
     99       for (v=e[i].v;fa[v]!=x;v=fa[v])
    100     sum+=f[fa[v]][idf[v]];
    101       for (j=0;j<=(1<<cnt)-1;j++)
    102     if ((j&idf[u])==0&&(j&idf[v])==0)
    103       {
    104         f[x][j]=max(f[x][j],f[x][j|idf[u]|idf[v]]+sum);
    105       }
    106     }
    107 }
    108 int main()
    109 {int i,u,v,d;
    110   //freopen("zyys.in","r",stdin);
    111   //freopen("zyys.out","w",stdout);
    112   cin>>n>>m;
    113   for (i=1;i<=m;i++)
    114     {
    115       scanf("%d%d%d",&u,&v,&d);
    116       if (!d) add(u,v),add(v,u);
    117       else e[++tot].u=u,e[tot].v=v,e[tot].d=d,ans+=d;
    118     }
    119   dfs1(1,0);dfs2(1,0,1);
    120   for (i=1;i<=tot;i++)
    121     {
    122       LCA=get_lca(e[i].u,e[i].v);
    123       if ((dep[e[i].u]+dep[e[i].v]-2*dep[LCA])%2==0)
    124     h[LCA].push_back(i);
    125     }
    126   DP(1,0);
    127   cout<<ans-f[1][0];
    128 }
  • 相关阅读:
    Aster寻路算法1(转)
    谈谈项目纵向项目验收
    要有兴趣
    用c# 操作 文件的方法
    使用ACT进行测试
    Generated servlet error: keyword cannot be resolved or is not a type
    米尔顿艾瑞克森的催眠引导词
    c# webcliend 来制作 网页搜捕器
    网页木马的解决方案
    用Swing实现数据表格功能
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8575602.html
Copyright © 2011-2022 走看看