5 10 50 10 40 10 40 20 65 30 70 30 1 2 1 3 2 4 2 5 1 1 20 7 -1 -1
50 7
//重要的状态转换式,DP //GetBrain(parent, Soldier) = max{ GetBrain(parent, Soldier-send) + GetBrain(son, send) } //1<=send<=Soldier-cost(parent),son是parent的儿子节点 } //Gain[i][j]表示(i,j,Gain[i][j])=j个士兵在i节点上获得了Gain[i][j]宝藏 #include<iostream> #include<algorithm> #include<string> #include<vector> using namespace std; const int N = 110; int n,SodierSum,Gain[N][N],bug[N],brain[N]; vector<int> g[N]; /*邻接表,g[i][0]存放的是与i邻接的结点数目,从1开始存放结点 2 2-> 5 2 1-> 5-> 3-> 4 2 2-> 4 3 2-> 5-> 3 3 4-> 1-> 2 */ bool visited[N]; void init() { memset(visited,false,sizeof(visited)); memset(Gain,0,sizeof(Gain)); for(int i=0;i<=n;++i) g[i].clear(); } void dfs(int root) { visited[root]=true; int size=g[root].size(); //节点代价,需要派出的士兵数量,向上取整 int cost=(bug[root]+19)/20; //如果士兵无法击败bugs,当然无法获得宝藏 if( SodierSum < cost ) return ; //从cost数起,因为sodier的数量必须>=cost才能获得宝藏 //只要士兵数>=cost,所获宝藏是一样的,都是brain[root] for(int i=cost;i<=SodierSum;++i) Gain[root][i]=brain[root]; for(int i=0;i<size;++i) { int son=g[root][i];//找邻接点,用二维数组存图,实际上类似链式存储 if(visited[son]) continue; dfs(son); //dfs+dp思想 for(int sodier=SodierSum;sodier>=cost;--sodier)//根节sodier数 { for(int send=1;send<=sodier-cost;send++)//派出去的士兵最多sodier-cost,因为至少要留下cost人在父节点 //状态转移,核心 if( sodier - send >= cost) //留守的士兵应该>=cost,题目要求. Gain[root][sodier]=max(Gain[root][sodier],Gain[root][sodier-send]+Gain[son][send]); } } } int main() { int x,y; while(scanf("%d %d",&n,&SodierSum)==2) { if(n==-1 && SodierSum==-1) break; for(int i=1;i<=n;++i) scanf("%d %d",&bug[i],&brain[i]); init(); for(int root=1;root<n;root++) { scanf("%d %d",&x,&y); g[x].push_back(y); g[y].push_back(x); } if(SodierSum==0)//没有人就不可能获得brain { printf("0\n"); continue; } else { dfs(1); cout << Gain[1][SodierSum] << endl; } } return 0; }
#include<iostream> using namespace std; const int MAXN=110; int N,M; struct Node { int number; //number:该结点的bug数 int p; //p:该结点的possible; }; Node node[MAXN];//记录结点 int dp[MAXN][MAXN];//DP,dp[i][j]表示根结点为i时,用掉j个士兵获得的最大值 int adj[MAXN][MAXN];//存树 。adj[i][j]:结点为i,adj[i][0]表示该结点所连接的结点(父结点和子结点一共)个数 //类似链式存储 /* 3 1-> 2-> 3 5 3-> 4-> 5-> 6-> 7 6 9-> 4-> 3-> 2-> 5-> 6 */ //adj[i][j](j>=1)表示结点编号,j=结点个数+1 bool vis[MAXN];//访问标记 int max(int a, int b) { return a>b ? a:b; } void dfs(int root)//DFS,求该结点及其分支所能获得的最大possible { vis[root]=true;//已经访问 int cost=(node[root].number+19)/20;//获得该结点需要的士兵数目 //士兵数只要能击败bugs,则brain可以全获 for(int i=cost;i<=M;i++) dp[root][i]=node[root].p;//用掉i个士兵获得的possible for(int i=1;i<=adj[root][0];i++)//adj[root][0]表示root结点的邻接节点数 { int u=adj[root][i];//典型的链式存储形式 if(vis[u]) continue; //跳过已访问的 dfs(u); //求该子结点的最大possible for(int j=M;j>=cost;j--)//父节点的士兵数 { for(int k=1;k<=M-cost;k++)//派出的士兵数k,至少要派出1个士兵才能获得下面的宝藏,从1开始,注意!! { //状态转移式,重点!DP思想 if( j-k >= cost ) //留守士兵数应该>=cost dp[root][j]=max(dp[root][j],dp[root][j-k]+dp[u][k]); } } } } int main() { int b,e; while(cin >> N >> M) { if(N==-1&&M==-1) break; memset(vis,false,sizeof(vis)); memset(dp,0,sizeof(dp)); memset(adj,0,sizeof(adj)); for(int i=1;i<=N;i++) cin >> node[i].number >>node[i].p; for(int i=1;i<N;i++)//存图 { cin >> b >> e;//连接结点b和e adj[b][0]++; //链表+1 adj[b][adj[b][0]]=e;//在b链表末尾存下一个结点e adj[e][0]++; //链表+1 adj[e][adj[e][0]]=b;//互连 } if(M==0)//这个必需要,有代价为0的房间,M=0则无法获得 cout << 0 << endl; else { dfs(1); cout << dp[1][M] << endl; } } return 0; }
solution 3:
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<math.h> #include<algorithm> #include<string.h> using namespace std; int map[110][110]; int bug[110]; int bra[110]; int vis[110]; int dp[110][110]; int n,m; //dp[i][j]表示在i洞派出j个骑兵获取的brain值 //动态规划转移式 //dp[i][j]=max{dp[x][j],dp[x][j-k]+dp[i][k]}; void dfs(int x,int pre)//记录上一次visited的结点,如果这次visit的和上一次相同,则继续下一个. { int tr=(bug[x]+19)/20; for(int i=m;i>=tr;i--)//初始化收益 dp[x][i]=bra[x]; //士兵数只要能击败bugs,则brain可以全获 for(int i=1;i<=n;++i) { if(map[x][i]&&pre!=i) { dfs(i,x); for(int j=m;j>=tr;j--) { for(int k=1;k<=j-tr;k++) { dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[i][k]); } } } } } int main() { while(cin>>n>>m && (n!=-1||m!=-1)) { for(int i=1;i<=n;i++) cin>>bug[i]>>bra[i]; int a,b; memset(map,0,sizeof(map)); memset(dp,0,sizeof(dp)); for(int i=1;i<n;i++) { cin>>a>>b; map[a][b]=1;//建邻接矩阵 map[b][a]=1; } if(m==0) { cout<<0<<endl; continue; } dfs(1,-1); cout<<dp[1][m]<<endl; } return 0; }