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 }