uva10859 Placing Lampposts (樹形dp+求兩者最小值方法)

題目鏈接:點擊打開鏈接

題意:給你一個n個點m條邊的無向無環圖,在儘量少的節點上放燈,使得所有邊都被照亮,每盞燈將照亮以它爲一個端點的所有邊。在燈的總數最小的前提下,被兩盞燈同時照亮的邊數應儘量大。

思路:無向無環圖的另一個說法是“森林”,即由多棵樹組成,我們可以先算一棵樹上的答案,然後累加起來就行了。本題的優化目標有兩個:放置的燈數應儘量少,被兩盞燈照亮的邊數b應儘量大。爲了統一起見,我們把後者替換爲:恰好被一盞燈照亮的邊數c應儘量少,然後用x=M*a+c作爲最小化的目標,其中M是一個很大的正整數。當x取到最小值時,x/M的整數部分就是放置的燈數的最小值;x%M就是恰好被一盞燈照亮的邊數的最小值。

下面的思路和白書上有點不同:

我們可以用dp[i][j]表示點i的狀態爲j時,以點i爲根節點的最小x,那麼如果j是1,子節點的狀態既可以是0,也可以是1,如果j是0,那麼子節點的狀態只能是1。vector<int>vec存邊比鄰接表方便很多啊..

還有一點要注意,如果當前求的樹只有一個節點,那麼不用把在這個點上放燈,因爲題目只要求把邊照亮。


#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<string>
#include<bitset>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef long double ldb;
#define inf 99999999
#define pi acos(-1.0)
#define maxn 2010
#define M 2000
vector<int>vec[maxn];
vector<int>::iterator it;
int dp[maxn][2];
int vis[maxn];

void dfs(int u,int father,int f)
{
    int i,j,x,v;
    vis[u]=1;
    dp[u][1]=dp[u][0]=inf;
    if(vec[u].size()==0){
        dp[u][1]=dp[u][0]=0;return;
    }
    if(vec[u].size()==1 && vec[u][0]==father){
        if(f==0){
            dp[u][1]=M;
        }
        else if(f==1){
            dp[u][0]=0;
            dp[u][1]=M;
        }
    }
    else{
        if(f==0){
            dp[u][1]=M;
            for(i=0;i<vec[u].size();i++){
                if(vec[u][i]==father)continue;
                v=vec[u][i];
                dfs(v,u,1);
                dp[u][1]+=min(dp[v][1],dp[v][0]+1);
            }
        }
        else if(f==1){
            dp[u][1]=M;
            for(i=0;i<vec[u].size();i++){
                if(vec[u][i]==father)continue;
                v=vec[u][i];
                dfs(v,u,1);
                dp[u][1]+=min(dp[v][1],dp[v][0]+1 );
            }

            dp[u][0]=0;
            for(i=0;i<vec[u].size();i++){
                if(vec[u][i]==father)continue;
                v=vec[u][i];
                dfs(v,u,0);
                dp[u][0]+=dp[v][1]+1;
            }
        }
    }
}


int main()
{
    int n,m,i,j,T,c,d;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++){
            vec[i].clear();
        }
        for(i=1;i<=m;i++){
            scanf("%d%d",&c,&d);
            c++;d++;
            vec[c].push_back(d);
            vec[d].push_back(c);
        }
        for(i=1;i<=n;i++)vis[i]=0;
        int x=0;
        for(i=1;i<=n;i++){
            if(vis[i])continue;
            dfs(i,0,1);
            x+=min(dp[i][0],dp[i][1]);
        }
        printf("%d %d %d\n",x/2000,m-x%2000,x%2000);
    }
    return 0;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章