UVA 10859 Placing Lampposts(树形DP)

题意:

       给定一张有向无环图,每个节点视作一个路口,每条边视作路,要求挑选一些节点放置路灯,使每条路都能被路灯照到,且使用的路灯数最少,如若存在使用相同路灯数的情况,则使得能被两盏路灯照到的路的数量尽量多。


解题:

      可以将此问题提炼一下,就是使用最少的路灯照亮所有的路,使得被两盏路灯照亮的路尽量多,也就是使被一盏路灯照亮的路尽量少。那么问题可以转换为,使用最少x盏路灯,使得最少为y条路被一盏路灯照亮。那么问题就抽象为,W=k*x+y(其中k>y)使得W尽量小。因为,k>y,也就保障了x为首要条件。dp[i][0]表示第i个节点不选,dp[i][1]表示第i个节点选的最小值。当一个节点其父节点为不选时,那么它必选,因为若不选,那么他们之间的路就无法照亮了,倘若父节点选了,那么该节点可选可不选,取两者间的小者,若相同,那么则选选的,因为这样被两盏灯照亮的路径数多。


代码:

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <cstdio>
#include <cstring>
#include <map> 
#define inf 0x3f3f3f3f
using namespace std;
int n,m,head[1010],cnt,nxt[2020],dp[1010][2];
bool vis[1010];
struct edge
{
	int fm,to;
}store[2020];
int min(int a,int b)
{
	return a<b?a:b;
}
void add_edge(int x,int y)
{
	nxt[cnt]=head[x];
	head[x]=cnt;
	store[cnt].fm=x;
	store[cnt].to=y;
	cnt++;
	nxt[cnt]=head[y];
	head[y]=cnt;
	store[cnt].fm=y;
	store[cnt].to=x;
	cnt++;
}
void dfs(int x)
{
	int to;
	vis[x]=1;
  	dp[x][0]=0;
  	dp[x][1]=1010;
  	for(int i=head[x];~i;i=nxt[i])
  	{
	  	to=store[i].to;
	  	if(vis[to])continue;
        dfs(to);
        dp[x][0]+=dp[to][1]+1;//一盏灯照亮 
		if(dp[to][0]<dp[to][1])
			dp[x][1]+=dp[to][0]+1; //单盏灯亮的情况 
		else
		    dp[x][1]+=dp[to][1];  //相等的情况下,选择不加1     
    }
}
int main()
{
    int t,a,b,ans;
	scanf("%d",&t);
	while(t--)
	{
		cnt=ans=0;
		scanf("%d%d",&n,&m);
		memset(head,-1,sizeof(head));
		memset(vis,0,sizeof(vis));
		memset(nxt,-1,sizeof(nxt));
		for(int i=0;i<m;i++)
		{
			scanf("%d%d",&a,&b);
			add_edge(a,b);
		}
		for(int i=0;i<n;i++)
		{
			if(!vis[i])
			{
			  dfs(i);
	          ans+=min(dp[i][0],dp[i][1]);
			}
		}
		printf("%d %d %d\n",ans/1010,m-ans%1010,ans%1010);
	} 
	return 0;
}


你可能感兴趣的:(动态规划,uva)