1. 程式人生 > >SPOJ 1479 +SPOJ 666 無向樹最小點覆蓋 ,第二題要方案數,樹形dp

SPOJ 1479 +SPOJ 666 無向樹最小點覆蓋 ,第二題要方案數,樹形dp

題意:求一顆無向樹的最小點覆蓋。 

  本來一看是最小點覆蓋,直接一下敲了二分圖求最小割,TLE。      

   樹形DP,叫的這麼玄乎,本來是線性DP是線上往前\後推,而樹形DP就是在樹上,由葉子結點狀態向根狀態推。

 dp[u][1/0]:表示,結點u,1:選擇,0,:不選。dp值是以改點為根(目前為止,dfs遍歷順序自然決定了樹的層)的已經選擇點數,自然開始時不知道,對每個點,初值dp[u][0]=0、

dp[u][1]=1,回溯的時候:

                  1:dp[u][1]+=min(dp[v][1],dp[v][0]);該節點選擇了,那麼子節點可選可不選。

                   2:dp[u][0]+=dp[v][1];該節點沒有選擇,則其子節點必需選擇。

#include<iostream>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
using namespace std;
int n; 
vector<vector<int> >v(100010);
int vis[100010];
int dp[100010][2];          
inline int minn(int a,int b)
{
    if(a<b)return a;
    return b;
}
void dfs(int u)
{
    dp[u][0]=0;          //不放,0個
    dp[u][1]=1;         //放一個,
    for(int i=0;i<v[u].size();i++)
    {
        int vv=v[u][i];
        if(!vis[vv])
           {
               vis[vv]=1;
               dfs(vv);
          dp[u][0]+=dp[vv][1];          //回溯時加上
          dp[u][1]+=minn(dp[vv][1],dp[vv][0]);
           }
    }
}
int main()
{
    scanf("%d",&n);
    int tx,ty;
    for(int i=0;i<n-1;i++)
       {
           scanf("%d%d",&tx,&ty);
           v[tx].push_back(ty);
           v[ty].push_back(tx);
       }
       vis[1]=1;
       dfs(1);
    cout<<minn(dp[1][0],dp[1][1]);  //結果為根放與不放的狀態最小值
       return 0;
}

      666,求最優時候方案數,

     多一個DP方程即可。

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
int n;
vector<vector<int> >v(100020);
int vis[100020];
struct state
{
    int light;
    int count;
};
state dp[100020][2];
inline int minn(int a,int b)
{
    if(a<b)return a;
    return b;
}
void dfs(int u)
{
    dp[u][0].light=0;          //不放,0個
    dp[u][1].light=1;         //放一個,
    dp[u][0].count=dp[u][1].count=1;
    for(int i=0;i<v[u].size();i++)
    {
        int vv=v[u][i];
        if(!vis[vv])
           {
               vis[vv]=1;
               dfs(vv);
          dp[u][0].light+=dp[vv][1].light;          //回溯時加上
          dp[u][1].light+=minn(dp[vv][1].light,dp[vv][0].light);

          dp[u][0].count= dp[u][0].count*dp[vv][1].count%10007;

         if(dp[vv][1].light<dp[vv][0].light)
           dp[u][1].count=dp[u][1].count*dp[vv][1].count%10007;

         else if (dp[vv][1].light>dp[vv][0].light)
           dp[u][1].count=dp[u][1].count*dp[vv][0].count%10007;

         else
           dp[u][1].count=dp[u][1].count*(dp[vv][0].count+dp[vv][1].count)%10007;

           }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
          int tx,ty;
         for(int i=0;i<=n;i++)
       {
           v[i].clear();vis[i]=0;
       }
       for(int i=0;i<n-1;i++)
       {
           scanf("%d%d",&tx,&ty);
           v[tx].push_back(ty);
           v[ty].push_back(tx);
        }
       vis[1]=1;
       dfs(1);
     int ans1=minn(dp[1][0].light,dp[1][1].light);  //結果為根放與不放的狀態最小值
     if(dp[1][0].light<dp[1][1].light)
     {
         printf("%d %d\n",ans1,dp[1][0].count);
     }
     else if(dp[1][0].light>dp[1][1].light)
     {
         printf("%d %d\n",ans1,dp[1][1].count);
     }
     else
     {
         int ans2= (dp[1][0].count%10007+dp[1][1].count%10007)%10007;
         printf("%d %d\n",ans1,ans2);
     }
    }
       return 0;
}

相關推薦

SPOJ 1479 +SPOJ 666 覆蓋 ,第二方案,樹形dp

題意:求一顆無向樹的最小點覆蓋。    本來一看是最小點覆蓋,直接一下敲了二分圖求最小割,TLE。          樹形DP,叫的這麼玄乎,本來是線性DP是線上往前\後推,而樹形DP就是在樹上,由葉子結點狀態向根狀態推。  dp[u][1/0]:表示,結點u,1:選擇,0

【CodeChef】Annual Parade -費用大流&覆蓋

傳送門:Annual Parade 題解 求鏈覆蓋所有點的最小花費,考慮拆點跑最小費用最大流。 1 0

割集解法

from: http://www.cppblog.com/imky/archive/2010/08/14/123414.html 無向圖最小點割集,確定起點S,終點T。每個點都有自己的點權值vi,求最小點權和的割點集,使得S無法到達T。 解法:將每個點拆分為兩個點v和v',

hdu6311(路徑覆蓋->尤拉路徑->fleury 尤拉路徑模板)

這題主要是個套路。。就是求無向圖最小路徑覆蓋。。 與有向圖的二分圖做法不同,這個是轉化為求最少的尤拉路徑。。 尤拉圖有個結論是尤拉路徑的個數為度為奇數的點的個數/2(可以類比歐拉回路的結論) 然後求尤拉路徑的方法是fleury演算法。。其思想就是暴力dfs,然後巧妙的地

[HDOJ6081] 度度熊的王國戰略(割,據水)

eof printf ret pri sin %d logs ems ++ 題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=6081 無向圖求割點,應該是個論文題,16年有一篇SW算法+斐波那契堆優化的論文。 但是這數據怎麽這!

poj1966Cable TV Network——割(大流)

一個 can struct div ret memcpy AI ostream () 題目:http://poj.org/problem?id=1966 把一個點拆成入點和出點,之間連一條邊權為1的邊,跑最大流即最小割; 原始的邊權賦成inf防割; 枚舉源點和匯點,直接相鄰

藍書(演算法競賽進階指南)刷記錄——POJ1734 Sightseeing trip(環)

題目:poj1734. 題目大意:給定一張無向圖,求這張無向圖邊權和最小的節點大於3個的環,若有解輸出任意一個方案,否則輸出“No solution.”. 這就是一個較為簡單的floyd應用. 我們可以先把floyd模板寫下來看看floyd有什麼特殊的性質: void floyd

poj1734

要求對floyd演算法有一定的理解。 有一個神奇的地方:路徑是邊做邊更新的,防止了出現重複的點。(在不同的k時更新的路徑,中間點g[i][j]是會變化的) #include<bits/stdc++.h> using namespace std; #define

HDU 3435 權值覆蓋

An undirected graph is a graph in which the nodes are connected by undirected arcs. An undirected arc is an edge that has no arrow. Both e

12.3日+佛洛依德處理環+dijkstra處理有

  昨天的資料庫考試,題目本身都簡單的,但是感覺時間有點緊張,可能和自己有點墨跡有關。題目不怕不會做,就怕讀錯題,上了大學養成了考試“做完一遍要檢查的壞習慣”,這次沒時間檢查,所以有種做的不好的感覺。       弗洛伊德演算法是運用的動態規劃的思

HDU-1599-find the mincost route【短路】【環】

find the mincost route Time Limit: 1000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4341 

【USACO4.1.3】籬笆迴路

題目意思就是讓你求無向圖最小環,但是給資料的方式非常噁心。 我的用並查集+暴力的方式…… 先給每個邊的頂點標號,然後……  把A能到B,B也能到A的邊的點,給併為一個點…… 然後floyd求最小環。 floyd最小環我自己還不是非常理解…… 但是先用著,上課再想

【杭電oj1599】find the mincost route

           find the mincost route Time Limit: 1000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s

floyd求環——poj1734

給定一個無向圖,求出圖中由 3個及以上個點構成的環的邊權和 中的最小值。(一個點不能遍歷多次)在floyd時,先迴圈k,然後是i和j,你會發現在每次進入一個新的k迴圈時,每一個d(i,j)都儲存著從i到j,只經歷了編號不超過k-1的節點的最短路、於是,min{d(i,j)+

poj 2914

最小割集◎Stoer-Wagner演算法 一個無向連通網路,去掉一個邊集可以使其變成兩個連通分量則這個邊集就是割集;最小割集當然就權和最小的割集。 可以用最小切割最大流定理: 1.min=MAXINT,確定一個源點 2.列舉匯點 3.計算最大流,並確定當前源匯的最小割集,若比

    先解釋下名詞的意思。 無向圖的割:就是去掉一些邊,使得原圖不連通,最小割就是要去掉邊的數量最小。 解決這個問題的常用辦法就是Stoer-Wagner 演算法; 先說下這個演算法的步驟後面給出證明: 1.min=MAXINT,固定一個頂點P 2.從點P用類似prim的

大獨立集,覆蓋支配集 貪心and樹形dp

www 子節點 最大獨立集 com 倒序 最小支配集 交流 屬於 else 目錄 求樹的最大獨立集,最小點覆蓋,最小支配集 三個定義 貪心解法 樹形DP解法 (有任何問題歡迎留言或私聊&&歡迎交流討論哦 求樹的最大獨立集,最小點覆蓋,最小支配集 三個

支配集、覆蓋大獨立集 (貪心orDP)

樹的最小支配集:點集中取出儘量少的點,使剩下的點與取出來的點都有邊相連。 樹的最小點覆蓋:點集中取出儘量少的點,使得所有邊都與選出的點相連。 樹的最大獨立集:點集中取出儘量多的點,使得這些點兩兩之間沒有

支配集、覆蓋大獨立集【模板】

最小支配集:指從所有頂點中取儘量少的點組成一個集合,使得剩下的所有點都與取出來的點有邊相連。頂點個數最小的支配集被稱為最小支配集。這裡用貪心法來求。 1.以1號點深度優先搜尋整棵樹,求出每個點在DFS中的編號和每個點的父親節點編號。 2.按DFS的反向序列檢

支配集,覆蓋大獨立集

首先看一下三者的定義: 定義1 對於圖G=(V,E)來說, 最小支配集 指的是從V中取儘量少的點組成一個集合,使得對於V中剩餘的點都與取出來的點有邊相連。也就是說,設V‘是圖G的一個支配集,則對於