bzoj1808 [Ioi2007]training 训练路径

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

正解:状压$dp$。

这道题应该是去年某场考试考过的题,当时爆零了(似乎是因为没有小数据的暴力分。。

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

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

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

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

知道这个性质以后就不是那么难做了(虽然对于我来说还是很难

我们先把题意转化成用总边权减去最大留下的边权。

考虑一个条件,即每个点度数不超过$10$,这启发我们可以在树上维护儿子的状态。

于是考虑状压$dp$,设$f[i][S]$表示$i$这棵子树,不考虑状态$S$的集合的儿子(就是把这些儿子砍掉)的最大值。

我们考虑在$lca$处计算一条边的贡献,首先如果$lca$为$i$的所有边都不留,那么$f[i][S]=sum f[son][S]$。

然后我们依次考虑每一条边必须加的贡献,对于每一条边,设两个端点为$a,b$(如果有一个为$lca$就把这个点丢掉)。

那么我们的贡献就是$w+f[a]+f[b]$再加上所有$a$到$b$路径上的每个点(不包括$a,b,lca$)不考虑它在路径上的儿子的状态。

很显然,这条路径不能被其他非树边覆盖,所以我们就必须把这条路径上的树边都断开,把一个点的贡献加上的时候不能考虑路径上的其他点。

所以这道题我们就做完了,复杂度为$O(m*2^{10}+mn)$。

 1 #include <bits/stdc++.h>
 2 #define il inline
 3 #define RG register
 4 #define ll long long
 5 #define N (2005)
 6 
 7 using namespace std;
 8 
 9 vector<int> h[N];
10 
11 struct E{ int u,v,w; }e[5005];
12 struct edge{ int nt,to; }g[N<<1];
13 
14 int f[N][N],st[N],sz[N],fa[N],son[N],top[N],tid[N],dep[N],head[N],n,m,num,sum,tot;
15 
16 il int gi(){
17   RG int x=0,q=1; RG char ch=getchar();
18   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
19   if (ch=='-') q=-1,ch=getchar();
20   while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
21   return q*x;
22 }
23 
24 il void insert(RG int from,RG int to){
25   g[++num]=(edge){head[from],to},head[from]=num; return;
26 }
27 
28 il void dfs1(RG int x,RG int p){
29   fa[x]=p,sz[x]=1,dep[x]=dep[p]+1;
30   for (RG int i=head[x],v;i;i=g[i].nt){
31     v=g[i].to; if (v==p) continue;
32     dfs1(v,x),sz[x]+=sz[v];
33     if (sz[son[x]]<=sz[v]) son[x]=v;
34   }
35   return;
36 }
37 
38 il void dfs2(RG int x,RG int p,RG int anc){
39   top[x]=anc; if (son[x]) dfs2(son[x],x,anc);
40   for (RG int i=head[x],v;i;i=g[i].nt){
41     v=g[i].to; if (v!=p && v!=son[x]) dfs2(v,x,v);
42   }
43   return;
44 }
45 
46 il int lca(RG int u,RG int v){
47   while (top[u]!=top[v]){
48     if (dep[top[u]]<dep[top[v]]) swap(u,v);
49     u=fa[top[u]];
50   }
51   return dep[u]<dep[v] ? u : v;
52 }
53 
54 il void dfs(RG int x,RG int p){
55   RG int tot=0,sum;
56   for (RG int i=head[x];i;i=g[i].nt) if (g[i].to!=p) dfs(g[i].to,x);
57   for (RG int i=head[x];i;i=g[i].nt) if (g[i].to!=p) tid[g[i].to]=1<<tot,st[tot++]=g[i].to;
58   for (RG int i=(1<<tot)-1;~i;--i){
59     sum=0; for (RG int j=0;j<tot;++j) if (!(i>>j&1)) sum+=f[st[j]][0]; f[x][i]=sum;
60   }
61   for (RG int i=0,a=0,b=0,id,S=h[x].size();i<S;++i,a=b=0){
62     id=h[x][i],sum=e[id].w;
63     if (e[id].u!=x) for (sum+=f[a=e[id].u][0];fa[a]!=x;a=fa[a]) sum+=f[fa[a]][tid[a]];
64     if (e[id].v!=x) for (sum+=f[b=e[id].v][0];fa[b]!=x;b=fa[b]) sum+=f[fa[b]][tid[b]];
65     for (RG int j=(1<<tot)-1;~j;--j)
66       if (!(j&tid[a]) && !(j&tid[b])) f[x][j]=max(f[x][j],sum+f[x][j|tid[a]|tid[b]]);
67   }
68   return;
69 }
70 
71 int main(){
72 #ifndef ONLINE_JUDGE
73   freopen("training.in","r",stdin);
74   freopen("training.out","w",stdout);
75 #endif
76   n=gi(),m=gi();
77   for (RG int i=1,u,v,w;i<=m;++i){
78     u=gi(),v=gi(),w=gi(),sum+=w;
79     if (w) e[++tot]=(E){u,v,w};
80     if (!w) insert(u,v),insert(v,u);
81   }
82   dfs1(1,0),dfs2(1,0,1);
83   for (RG int i=1,G;i<=tot;++i){
84     G=lca(e[i].u,e[i].v);
85     if (!((dep[e[i].u]+dep[e[i].v]-(dep[G]<<1))&1)) h[G].push_back(i);
86   }
87   dfs(1,0),cout<<sum-f[1][0]; return 0;
88 }
原文地址:https://www.cnblogs.com/wfj2048/p/8483589.html