UVa:10859 Placing Lampposts(树形DP)

来源:互联网 发布:js自动登录脚本 编辑:程序博客网 时间:2024/05/16 18:55

树形DP。

子问题可以分为两类,即在u为根节点且在u点放置灯时的最小灯数、u为根节点且不在u点放置灯时的最小灯数。

这样用dp【u】【1】,dp【u】【0】分别表示这两种情况。用edge【u】【0/1】【1/2】表示这两种情况时同时被灯照亮一条边、两条边的个数。

dp【u】【0】可以由u的所有子节点的dp【i】【1】之和转移而来,即当该结点的所有子节点都放灯时,这个点可以不放灯。同时计算edge【u】【0】【1/2】,edge【u】【0】【2】可以直接等于其子节点的edge【i】【1】【2】之和,edge【u】【0】【1】等于子节点edge【i】【0】【1】之和还要加上子节点数。

dp【u】【1】可以由u的所有子节点的min{dp【i】【0/1】}之和转移而来,注意当dp【i】【0】==dp【i】【1】时,要比较edge【i】【0】【2】与edge【i】【1】【2】的大小再做选择。同时计算edge【u】【1】【1/2】。

无向无环图要转换成有根树来做,这样递归的时候要判断不是父亲节点。

注意一个很坑的地方,题目给的图可能不连通。

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <vector>#include <queue>#include <map>#include <algorithm>#define ll long long#define INF 2139062143#define inf -2139062144#define MOD 20071027#define MAXN 1005using namespace std;bool gl[MAXN][MAXN];bool node[MAXN];bool vis[MAXN][2];int dp[MAXN][2];int edge[MAXN][2][3];int n,m;int solve(int u,int v,int f){    if(vis[u][v]) return dp[u][v];    //edge[u][1]=edge[u][2]=0;    vis[u][v]=true;    if(v==0)    {        dp[u][0]=0;        edge[u][0][1]=edge[u][0][2]=0;        for(int i=0; i<n; ++i)            if(gl[u][i]&&i!=f)            {                dp[u][0]+=solve(i,1,u);                edge[u][0][2]+=edge[i][1][2];                edge[u][0][1]+=edge[i][1][1]+1;            }        return dp[u][0];    }    else if(v==1)    {        dp[u][1]=0;        edge[u][1][1]=edge[u][1][2]=0;        for(int i=0; i<n; ++i)            if(gl[u][i]&&i!=f)            {                int a=solve(i,1,u),b=solve(i,0,u);                if(a<b)                {                    dp[u][1]+=a;                    edge[u][1][2]+=edge[i][1][2]+1;                    edge[u][1][1]+=edge[i][1][1];                }                else if(a>b)                {                    dp[u][1]+=b;                    edge[u][1][2]+=edge[i][0][2];                    edge[u][1][1]+=edge[i][0][1]+1;                }                else                {                    dp[u][1]+=a;                    if(edge[i][1][2]>=edge[i][0][2])                    {                        edge[u][1][2]+=edge[i][1][2]+1;                        edge[u][1][1]+=edge[i][1][1];                    }                    else                    {                        edge[u][1][2]+=edge[i][0][2];                        edge[u][1][1]+=edge[i][0][1]+1;                    }                }            }        dp[u][1]++;        return dp[u][1];    }}int main(){    int T;   // freopen("outtt.txt","w",stdout);    scanf("%d",&T);    while(T--)    {        memset(gl,0,sizeof(gl));        memset(edge,0,sizeof(edge));        memset(dp,0,sizeof(dp));        memset(vis,0,sizeof(vis));        memset(node,0,sizeof(node));        scanf("%d%d",&n,&m);        for(int i=0; i<m; ++i)        {            int x,y;            scanf("%d%d",&x,&y);            gl[x][y]=gl[y][x]=true;            node[x]=node[y]=true;        }        int ans=0,x=0,y=0;        for(int i=0; i<n; ++i)            if(node[i]&&!vis[i][0])            {                if(solve(i,1,-1)<solve(i,0,-1))                {                    ans+=dp[i][1];                    x+=edge[i][1][2];                    y+=edge[i][1][1];                }                else if(solve(i,1,-1)>solve(i,0,-1))                {                    ans+=dp[i][0];                    x+=edge[i][0][2];                    y+=edge[i][0][1];                }                else                {                    if(edge[i][1][2]>=edge[i][0][2])                    {                        ans+=dp[i][1];                        x+=edge[i][1][2];                        y+=edge[i][1][1];                    }                    else                    {                        ans+=dp[i][0];                        x+=edge[i][0][2];                        y+=edge[i][0][1];                    }                }            }        printf("%d %d %d\n",ans,x,y);    }    return 0;}


 

0 0