标签:stack stream har force play 最大流 sed ace 出图
题意:给出一张完全图,所有的边的边权都是 y,现在给出图的一个生成树,将生成树上的边的边权改为 x,求一条距离最短的哈密顿路径。
先考虑x>=y的情况,那么应该尽量不走生成树上的边,如果生成树上有一个点的度数是n-1,那么必然需要走一条生成树上的边,此时答案为x+y*(n-2).
否则可以不走生成树上的边,则答案为y*(n-1).
再考虑x<y的情况,那么应该尽量走生成树上的边,由于树上没有环,于是我们每一次需要走树的一条路,然后需要从非生成树上的边跳到树的另一个点上去,
显然跳的越少越好,于是我们只需要找到树的最小路径覆盖,跳路径覆盖数-1次就可以了。
对于有向图的最小路径覆盖,一般是使用二分图匹配或者最大流来解决的。
而对于树的最小路径覆盖,可以用树形DP来解决。
令dp[x][0]表示x不与x的父亲构成路径的最小路径覆盖数,dp[x][1]表示x与x的父亲构成路径的最小路径覆盖数。
那么则有:
x没有儿子,dp[x][0]=dp[x][1]=1.
x只有一个儿子,dp[x][0]=dp[x][1]=dp[son[x]][1];
x有两个或者更多儿子,dp[x][0]=min(dp[son[x][i]][1]+dp[son[x][j]][1]+dp[son[x]][0])-1. dp[x][1]=min(dp[son[x][i]][1]+dp[son[x]][0]);
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <bitset> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi acos(-1.0) # define eps 1e-8 # define MOD 1000000007 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; int Scan() { int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } const int N=200005; //Code begin... struct Edge{int p, next;}edge[N<<1]; int head[N], cnt=1; int dee[N], sum, dp[N][2]; void add_edge(int u, int v){edge[cnt].p=v; edge[cnt].next=head[u]; head[u]=cnt++;} void dfs(int x, int fa){ int siz=0, sum=0, f=-INF, s=-INF; for (int i=head[x]; i; i=edge[i].next) { int v=edge[i].p; if (v==fa) continue; dfs(v,x); ++siz; sum+=dp[v][0]; if (dp[v][0]-dp[v][1]>f) s=f, f=dp[v][0]-dp[v][1]; else if (dp[v][0]-dp[v][1]>s) s=dp[v][0]-dp[v][1]; } if (siz==0) dp[x][0]=dp[x][1]=1; else { if (siz==1) dp[x][0]=sum-f, dp[x][1]=sum-f; else dp[x][0]=sum-f-s-1, dp[x][1]=sum-f; } } int main () { int n, x, y, u, v; scanf("%d%d%d",&n,&x,&y); FO(i,1,n) scanf("%d%d",&u,&v), add_edge(u,v), add_edge(v,u), ++dee[u], ++dee[v]; if (x>=y) { bool flag=false; FOR(i,1,n) if (dee[i]==n-1) flag=true; if (flag) printf("%lld\n",(LL)(n-2)*y+x); else printf("%lld\n",(LL)(n-1)*y); } else { dfs(1,0); printf("%lld\n",(LL)(dp[1][0]-1)*y+(LL)(n-dp[1][0])*x); } return 0; }
Codeforces 618D Hamiltonian Spanning Tree(树的最小路径覆盖)
标签:stack stream har force play 最大流 sed ace 出图
原文地址:http://www.cnblogs.com/lishiyao/p/6974144.html