1. 程式人生 > >Codeforces 618D Hamiltonian Spanning Tree(樹的最小路徑覆蓋)

Codeforces 618D Hamiltonian Spanning Tree(樹的最小路徑覆蓋)

n) cto 生成 ann 最小路徑 display add alt ext

題意:給出一張完全圖,所有的邊的邊權都是 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; }
View Code

Codeforces 618D Hamiltonian Spanning Tree(樹的最小路徑覆蓋)