uva 10859 - Placing Lampposts dp

题意:

  有n个节点,m条边,无向无环图,求最少点覆盖,并且在同样点数下保证被覆盖两次的变最多

分析:

1.统一化目标,本题需要优化目标有两个,一个最小灯数a,一个最大双覆盖边数b,一大一小,应该归一成,a及单覆盖边数c,\( x=Ma+c \) 为最小化目标,\( M>\Delta c \)

2.决策分析,只有两种放灯与不放,如不放灯则需要父节点必须放灯,故需要父节点状态,设\( f(i,j) \)为节点i在父节点状态为j时的最小x值,j为0代表不放灯,j为1代表放

  \begin{cases}
    sum\{d(k,0)|k为i所有子节点\}+(i为根节点?0:1)&,i不放灯\\
    sum\{d(k,1)|k为i所有子节点\}+M+(i不为根节点且j==0?1:0)&,i\ 放灯
    \end{cases}

 

 

代码如下

 1 /*

 2 author:jxy

 3 lang:C/C++

 4 university:China,Xidian University

 5 **If you need to reprint,please indicate the source**

 6 */

 7 #include <iostream>

 8 #include <cstdio>

 9 #include <cstdlib>

10 #include <cstring>

11 #include <algorithm>

12 using namespace std;

13 int n,m;

14 int first[1005];

15 int Next[2005],U[2005];

16 bool vis[1005][2];

17 int ans[1005][2];

18 int cnt;

19 int M=1<<11;

20 void add(int u,int v) //双向边

21 {

22     Next[cnt]=first[u]; first[u]=cnt; U[cnt++]=v;

23     Next[cnt]=first[v]; first[v]=cnt; U[cnt++]=u;

24 }

25 int dfs(int i,int j,int f)//i为当前节点,j为0代表父节点没放灯,为1代表放灯,f为-1代表根节点

26 {

27     if(vis[i][j])return ans[i][j];

28     vis[i][j]=1;

29     int k,&Ans=ans[i][j],ans0=0;

30     Ans=0;

31     for(k=first[i];~k;k=Next[k])

32     {

33         if(U[k]==f)continue;

34         Ans+=dfs(U[k],1,i);//放灯

35     }

36     Ans+=M;

37     if(~f)

38     {

39         if(j)ans0++;

40         else Ans++;

41     }

42     if(j||f==-1)

43     {

44         for(k=first[i];~k;k=Next[k])

45         {

46             if(U[k]==f)continue;

47             ans0+=dfs(U[k],0,i); //不放灯

48         }

49         Ans=min(Ans,ans0);

50     }

51     return Ans;

52 }

53 int main()

54 {

55     int T;

56     scanf("%d",&T);

57     int i,u,v;

58     while(T--)

59     {

60         cnt=0;

61         memset(vis,0,sizeof(vis));

62         memset(first,-1,sizeof(first));

63         scanf("%d%d",&n,&m);

64         for(i=0;i<m;i++)

65         {

66             scanf("%d%d",&u,&v);

67             add(u,v);

68         }

69         int Ans=0;

70         for(i=0;i<n;i++)

71         {

72             if(!vis[i][0])

73                 Ans+=dfs(i,0,-1);

74         }

75         printf("%d %d %d\n",Ans>>11,m-(Ans&(M-1)),Ans&(M-1));//Ans/M,m-Ans%M,Ans%M

76     }

77 }

 

你可能感兴趣的:(post)