Uva-10859-Placing Lampposts

这个题属于树形DP题,算是第二次做吧,也算是学习。

看了书上写的策略,理解了半天总算明白了。

其实有2个策略:

策略1:结点j不放灯。必须j=1或者是i是根结点时才允许作这个决策。此时dp(i,j)等于sum{d(k,0)|k取遍历i的所有子结点}。如果i不是根,还得加上1,因为结点i和其父亲结点这条边上只有一盏灯照亮。

策略2:结点i放灯。此时dp(i,j)等于 sum{dp(k,1)|k取遍i的所有子结点}+M。如果j=0且i不是根,还得加上1,因为结点i和其父结点这条边只有一盏灯照亮。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
using namespace std;
const int maxn=1e4+100;
int dp[maxn][2],n,m;
bool vis[maxn][2];
vector<int> a[maxn];
int DFS(int i,int j,int p)
{
    if(vis[i][j])
	return dp[i][j];
    vis[i][j]=1;
    int ans=2000;
    for(int k=0;k<a[i].size();k++)
	if(a[i][k]!=p)
	    ans+=DFS(a[i][k],1,i);
    if(!j&&p!=-1)
	ans++;
    if(j||p==-1)
    {
	int sum=0;
	for(int k=0;k<a[i].size();k++)
	    if(a[i][k]!=p)
		sum+=DFS(a[i][k],0,i);
	if(p!=-1)
	    sum++;
	ans=min(ans,sum);
    }
    dp[i][j]=ans;
    return ans;
}
int main()
{
    int cas;
    scanf("%d",&cas);
    while(cas--)
    {
	scanf("%d%d",&n,&m);
	for(int i=0;i<=n;i++)
	    a[i].clear();
	memset(vis,0,sizeof(vis));
	for(int i=0;i<m;i++)
	{
	    int ita,itb;
	    scanf("%d%d",&ita,&itb);
	    a[ita].push_back(itb);
	    a[itb].push_back(ita);
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	    if(!vis[i][0])
		ans+=DFS(i,0,-1);
	printf("%d %d %d\n",ans/2000,m-ans%2000,ans%2000);
    }
    return 0;
}


你可能感兴趣的:(树形DP)