您的位置:首页 > 其它

Uva-10859-Placing Lampposts

2013-03-26 18:20 274 查看
这个题属于树形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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: