UVa10895 Placing Lampposts
链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=34290
【思路】
树上DP+双重优化目标。
本题的特点就是有两个优化目标分别为:在尽量少的结点放灯、在此前提下有被两盏灯照亮的边最多。
首先进行转化:将第二个优化目标转化为在此前提下被一盏灯照亮的边最少。这样两个优化目标就都是求最小值。用一个hash(A,B)将两个新的优化目标AB映射到一个整数,转化为求这个整数的最小值,可以定义hash=A*M+B完成这个功能,M是一个较大数。
树上DP。设d[i][j]表示以i为根的子树且有父节点状态为j时的最优值,注意用j记录父节点状态。有如下转移式:
略。详见代码。
【代码】
1 #include<iostream> 2 #include<cstring> 3 #include<vector> 4 using namespace std; 5 6 const int maxn = 1000+10; 7 const int INF=1<<30; 8 const int M=2000; 9 10 vector<int> G[maxn]; 11 int d[maxn][2]; 12 bool vis[maxn][2]; 13 int n,m; 14 15 inline void init() { 16 for(int i=0;i<n;i++) G[i].clear(); 17 memset(vis,false,sizeof(vis)); 18 memset(d,0,sizeof(d)); 19 } 20 21 int dp(int i,int j,int fa) { 22 if(vis[i][j]) return d[i][j]; 23 vis[i][j]=true; 24 int &ans=d[i][j]; 25 26 //无论j都可以在i上放置街灯 27 ans=M; //放置一个街灯的价值 28 for(int k=0;k<G[i].size();k++) { 29 int v=G[i][k]; 30 if(v!=fa) { 31 ans += dp(v,1,i); 32 } 33 } 34 if(!j && fa>=0) ans++; //01 35 36 if(j || fa<0) //根也可以不放 37 { 38 int sum=0; 39 for(int k=0;k<G[i].size();k++) { 40 int v=G[i][k]; 41 if(v!=fa) { 42 sum += dp(v,0,i); 43 } 44 } 45 if(fa>=0) sum++; //10 //根不算 46 ans=min(ans,sum); //两种情况取min 47 } 48 49 return ans; 50 } 51 52 int main() { 53 ios::sync_with_stdio(false); 54 int T; cin>>T; 55 while(T--) 56 { 57 cin>>n>>m; 58 init(); 59 int u,v; 60 for(int i=0;i<m;i++) { 61 cin>>u>>v; 62 G[u].push_back(v); 63 G[v].push_back(u); 64 } 65 int ans=0; 66 for(int i=0;i<n;i++) if(!vis[i][0]) { 67 ans += dp(i,0,-1); 68 } 69 cout<<ans/M<<" "<<m-ans%M<<" "<<ans%M<<"\n"; 70 } 71 return 0; 72 }
原文:http://www.cnblogs.com/lidaxin/p/4896138.html