uva10859 Placing Lampposts

来源:互联网 发布:大数据在银行的应用 编辑:程序博客网 时间:2024/06/06 03:23

求一棵树的最小点覆盖(设为S0),在最小点覆盖相同的情况下使得同时被两个点覆盖的边尽量多(使得仅被一个点覆盖的边尽量少)

1.树形dp求点的最小覆盖子集

dp[i][j]:j状态下以i为顶点的子树最小点覆盖(S0')。j==1:i的父节点属于S0;j==1:i的父节点不属于S0。

状态转移的过程详细解释见代码注释

2.对于主要和次要极小值,可以用参数法使其变成一个变量:x=M*a+b,其中M是比b的变化范围大得多的常量。因此只有在a相等的情况下才会考虑到b的变化

#include<stdio.h>#include<iostream>#include<string.h>#include<algorithm>#include<map>#include<vector>#include<queue>#define maxn 1100#define maxm 10001#define ll long long#define sf scanf#define pf printf#define INF 0x3f3f3f3f#define mem(a,b) memset(a,b,sizeof(a))#define M 2000const ll mod=1000000000;#define clr(x) memset(x,0,sizeof(x))using namespace std;int t,n,m,ans;int d[maxn][maxn],vis[maxn][maxn];vector<int> g[maxn];int dp(int i,int j,int f){    if(vis[i][j]) return d[i][j];    int& ans=d[i][j];    vis[i][j]=1;    int sum1=0,sum0=0;//sum1记录放灯的值,sum0记录未放灯值    sum1=M;//此处放灯 min_lamp++ x+=M    for(int k=0;k<g[i].size();k++)        if(g[i][k]!=f) sum1+=dp(g[i][k],1,i);//该点放灯时子树的灯笼之和    if(!j&&f!=-1) sum1++;//如果父节点未放灯且该节点不是根节点 则min_onelamp++ x++    ans=sum1;    if(j||f==-1){        for(int k=0;k<g[i].size();k++){            if(g[i][k]!=f) sum0+=dp(g[i][k],0,i);<span style="font-family: Arial, Helvetica, sans-serif;">//该点未放灯时子树的灯笼之和</span>        }        if(f!=-1) sum0++;//该点未放灯 且不是根节点 <span style="font-family: Arial, Helvetica, sans-serif;">则min_onelamp++ x++</span>        ans=min(ans,sum0);//ans是该点放灯和未放灯中的最小值    }    return ans;}int main(){    scanf("%d",&t);    while(t--){        scanf("%d%d",&n,&m);        for(int i=0;i<n;i++) g[i].clear();        mem(vis,0);        ans=0;//ans=M*min_lamp+min_onelamp;        for(int i=0;i<m;i++){            int a,b;            scanf("%d%d",&a,&b);            g[a].push_back(b),g[b].push_back(a);        }        for(int i=0;i<n;i++)            if(!vis[i][0]) ans+=dp(i,0,-1);        printf("%d %d %d\n",ans/M,m-ans%M,ans%M);    }}


0 0
原创粉丝点击