UVA 10859 Placing Lampposts(树形DP)

来源:互联网 发布:mysql update 时间戳 编辑:程序博客网 时间:2024/05/16 17:01

题意:

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


解题:

      可以将此问题提炼一下,就是使用最少的路灯照亮所有的路,使得被两盏路灯照亮的路尽量多,也就是使被一盏路灯照亮的路尽量少。那么问题可以转换为,使用最少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 0x3f3f3f3fusing 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;}


0 0