某公司校招笔试题 树形递归4维DP 图论 烦人的分类讨论
来源:互联网 发布:唐嫣演技知乎 编辑:程序博客网 时间:2024/06/06 02:59
上上星期,一哥们找工作ing,参加各种公司的校招宣讲会,然而这次他参加完这个我名字都没听说过的公司的宣讲会后,该公司当场留了两道笔试题,让他们拿回来做,给5天时间,在上周五晚上12点前交上就行ORZ,全国收两百人,起薪35-40w。。。薪水简直不要太诱人,这令我怀疑这公司是做毒品国际贸易的。。。。。why u so diao???他让我帮他做的这两道题目我做了大半天,只会做一道,这是第二道,虽然自己的测试数据都过了,但是还不知道对不对,如果有不对的,希望评论区交流一下,欢迎hack。
____________________________________________________________________________________
正题在这(原稿不见了,凭记忆写):
题目描述:
有N<=1000个房间,互相联通,每个房间都有门通向其他房间,而且每个房间最多有三扇门,现在要安装M<=100个路由器,每个路由器的信号只能穿过一扇门。现在每个房间都有一个权值(1~10),现在要在房间里安装这些路由器,使得有信号的房间的权值和最大,输出这个最大值。
样例很容易读,12345是权值,然后跟N-1条边
sample input
5 1
1 2 3 4 5
2 1
3 2
4 2
5 3
sample output
10
解题思路:
这就是一个生成树,而且结点的度最多为3,我用DP的方法做的,就是一个dfs,同时记忆了一下数据。
我dp写了4维,方便实现,其实写两维就够了,额外还需要记录两个状态值。
dp[ i ][ j ]代表以第i点为根的这颗子树用不超过j个路由器,所能得到的最大值,后面的两维记录一下根结点的状态和最多两个(因为度为3,除去father,就剩下最多俩children)与他相邻的叶子结点的状态,状态里只要记录当前这个点是否有路由器、是否被叶子结点的路由器辐射到就行了,然后更新公式都在我下面的注释里,好烦。
最后要注意一下,要从一个度为1或2的起点开始dfs,不能随便找,万一找到一个度为3的当根,就炸了。
#include <iostream>#include <stdio.h>#include <math.h>#include <stdlib.h>#include <string>#include <string.h>#include <algorithm>#include <vector>#include <queue>#include <iomanip>#include <time.h>#include <set>#include <map>#include <stack>using namespace std;typedef long long LL;const int INF=0x7fffffff;const int MAX_N=10000;int N,M;int S[1009];vector<int>G[1009];int dp[1009][102][2][2];//第i个点为根向下组成的树,用不超过j个路由器,k=1选自己,k=0不选自己,l=1代表自己被关联覆盖掉int father[1009];int du[1009];//记录度数,以便从一个度为1的开始int solve(int root,int num,int choose,int cover){ //cout<<"dfs "<<root<<" "<<num<<" "<<choose<<" "<<cover<<endl; if(dp[root][num][choose][cover]!=-1)return dp[root][num][choose][cover]; if(num==0)return dp[root][num][choose][cover]=0;//0个路由器直接返回0 int Size=G[root].size(); int children_num=0; int children_ID[2]; for(int i=0;i<Size;i++){ if(father[G[root][i]]==root){ children_ID[children_num++]=G[root][i]; } if(father[G[root][i]]==0){ father[G[root][i]]=root; children_ID[children_num++]=G[root][i]; } } //cout<<"childnum="<<children_num<<endl; if(children_num==0){ for(int i=1;i<=M;i++){//用几个路由器 dp[root][i][1][1]=S[root]; dp[root][i][1][0]=S[root]; } } else if(children_num==1){ int child=children_ID[0]; for(int i=1;i<=M;i++){//共用几个路由器 //选自己,max=max((选了孩子,没选孩子且孩子被覆盖),没选孩子且孩子没被覆盖) dp[root][i][1][1]=max(max((solve(child,i-1,1,1)+S[root],solve(child,i-1,0,1)+S[root]),solve(child,i-1,0,0)+S[root]+S[child]),dp[root][i][1][1]); //不选自己且自己被覆盖,max=(选了孩子且孩子被覆盖) dp[root][i][0][1]=solve(child,i,1,1)+S[root]; //不选自己且自己不被覆盖,max=(没选孩子且孩子被覆盖,没选孩子且孩子没被覆盖) dp[root][i][0][0]=max(max(solve(child,i,0,1),solve(child,i,0,0)),dp[root][i][0][0]); } } else{//num==2 int child1=children_ID[0]; int child2=children_ID[1]; for(int i=1;i<=M;i++){//共用i个 //选自己 for(int j=0;j<=i-1;j++){//左边用j个,右边用i-1-j个 //选了左且没选右且右孩子已经被覆盖,选了左没选右且右孩子没被覆盖 int cur1=max(solve(child1,j,1,1)+solve(child2,i-1-j,0,1)+S[root],solve(child1,j,1,1)+solve(child2,i-1-j,0,0)+S[root]+S[child2]); //选了右且没选左且左孩子已经被覆盖,选了右没选左且左孩子没被覆盖 int cur2=max(solve(child2,i-1-j,1,1)+solve(child1,j,0,1)+S[root],solve(child2,i-1-j,1,1)+solve(child1,j,0,0)+S[root]+S[child1]); //两边都没选且左孩子被覆盖且右孩子已经被覆盖,两边都没选且左孩子被覆盖且右孩子没被覆盖 int cur3=max(solve(child1,j,0,1)+solve(child2,i-1-j,0,1)+S[root],solve(child1,j,0,1)+solve(child2,i-1-j,0,0)+S[root]+S[child2]); //两边都没选且左孩子没被覆盖且右孩子已经被覆盖,两边都没选且左孩子没被覆盖且右孩子没被覆盖 int cur4=max(solve(child1,j,0,0)+solve(child2,i-1-j,0,1)+S[root]+S[child1],solve(child1,j,0,0)+solve(child2,i-1-j,0,0)+S[root]+S[child1]+S[child2]); //两边都选了 dp[root][i][1][1]=max(max(max(max(max(cur1,cur2),cur3),cur4),solve(child1,j,1,1)+solve(child2,i-1-j,1,1)+S[root]),dp[root][i][1][1]); } //不选自己 for(int j=0;j<=i;j++){//左边用j个右边用i-j个 //自己被覆盖 //选了左且没选右且右孩子已经被覆盖,选了左没选右且右孩子没被覆盖 int cur1; if(j>0)cur1=max(solve(child1,j,1,1)+solve(child2,i-j,0,1)+S[root],solve(child1,j,1,1)+solve(child2,i-j,0,0)+S[root]); else { cur1=max(solve(child1,j,1,1)+solve(child2,i-j,0,1),solve(child1,j,1,1)+solve(child2,i-j,0,0)); } //if(root==3)cout<<"root3cur1"<<cur1<<" child1"<<child1<<endl; //选了右且没选左且左孩子已经被覆盖,选了右没选左且左孩子没被覆盖 int cur2; if(i-j>0)cur2=max(solve(child2,i-j,1,1)+solve(child1,j,0,1)+S[root],solve(child2,i-j,1,1)+solve(child1,j,0,0)+S[root]); else{ cur2=max(solve(child2,i-j,1,1)+solve(child1,j,0,1),solve(child2,i-j,1,1)+solve(child1,j,0,0)); } //if(root==3)cout<<"root3cur2"<<cur2<<endl; //自己没被覆盖 //两边都没选且左孩子被覆盖且右孩子已经被覆盖,两边都没选且左孩子被覆盖且右孩子没被覆盖 int cur3=max(solve(child1,j,0,1)+solve(child2,i-j,0,1),solve(child1,j,0,1)+solve(child2,i-j,0,0)); //两边都没选且左孩子没被覆盖且右孩子已经被覆盖,两边都没选且左孩子没被覆盖且右孩子没被覆盖 int cur4=max(solve(child1,j,0,0)+solve(child2,i-j,0,1),solve(child1,j,0,0)+solve(child2,i-j,0,0)); //两边都选了 int cur5=solve(child1,j,1,1)+solve(child2,i-j,1,1)+S[root]; //if(root==3)cout<<"root3cur5"<<cur5<<endl; dp[root][i][0][1]=max(max(max(cur1,cur2),cur5),dp[root][i][0][1]); dp[root][i][0][0]=max(max(cur3,cur4),dp[root][i][0][0]); } } } return dp[root][num][choose][cover];}int main(){ while(scanf("%d%d",&N,&M)!=EOF){ memset(dp,-1,sizeof(dp)); memset(father,0,sizeof(father)); memset(du,0,sizeof(du)); for(int i=1;i<=N;i++){ G[i].clear(); } for(int i=1;i<=N;i++){ scanf("%d",&S[i]); } for(int i=1;i<=N-1;i++){ int x,y; scanf("%d%d",&x,&y); G[x].push_back(y); G[y].push_back(x); du[x]++; du[y]++; } int start; for(int i=1;i<=N;i++){ if(du[i]==1){//从一个度为1的开始dfs start=i; father[start]=-1; break; } } cout<<max(solve(start,M,0,1),solve(start,M,0,0))<<endl; } return 0;}
- 某公司校招笔试题 树形递归4维DP 图论 烦人的分类讨论
- 某公司的笔试题
- 某公司的一个笔试题
- 某公司的iOS笔试题
- 讨论:烦人的细节
- 某公司的笔试题目
- 某公司笔试题
- 某公司笔试题
- 某公司笔试题
- 【某公司C++笔试题】
- 某公司C++笔试题
- 某公司java笔试题
- 某公司笔试题
- C++某公司笔试题
- 某公司笔试题
- 某公司笔试题
- 某公司笔试题
- 某公司笔试题
- Linux笔记
- linux hadoop集群简单几步完成SSH配置
- oracle
- Oracle普通表->分区表转换(9亿数据量)
- LTE CQI vs PMI vs RI-Difference between LTE CQI,PMI,RI
- 某公司校招笔试题 树形递归4维DP 图论 烦人的分类讨论
- Python3.5安装numpy和scripy等扩展包
- HDU 4027 Can you answer these queries? (线段树)
- hibernate总结
- Servlet-JSP相关
- Android面试常见知识点【二】(不定期更新)
- KoaHub.JS基于Node.js开发的Koa 生成验证码插件代
- Spring中ReloadableResourceBundleMessageSource的使用
- javaWeb之JAVA实现验证码的制作