选课 && 有线电视网

 

题目描述

在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习。现在有N门功课,每门课有个学分,每门课有一门或没有直接先修课(若课程a是课程b的先修课即只有学完了课程a,才能学习课程b)。一个学生要从这些课程里选择M门课程学习,问他能获得的最大学分是多少?

输入输出格式

输入格式:

 

第一行有两个整数N,M用空格隔开。(1<=N<=300,1<=M<=300)

接下来的N行,第I+1行包含两个整数ki和si, ki表示第I门课的直接先修课,si表示第I门课的学分。若ki=0表示没有直接先修课(1<=ki<=N, 1<=si<=20)。

 

输出格式:

 

只有一行,选M门课程的最大得分。

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<vector> 
 4 #include<cstring>
 5 using namespace std;
 6 const int maxn=1007;
 7 int score[maxn],f[maxn][maxn];
 8 int n,m;
 9 vector<int>son[maxn];
10 void search(int x){
11     f[x][0]=0;f[x][1]=score[x];
12     for(int i=0;i<son[x].size();i++){
13         int y=son[x][i];
14         search(y);
15         for(int u=m;u>=2;u--) 
16             for(int v=u-1;v>=0;v--)
17                 if(u>=v) f[x][u]=max(f[x][u],f[x][u-v]+f[y][v]);
18         if(x==0){
19         for(int j=m;j>=0;j--)
20             f[x][j]=max(f[x][j],f[x][0]+f[y][j]); 
21         } 
22     }
23 }
24 int main(){
25     cin>>n>>m;
26     for(int i=1;i<=n;i++){
27         int fa;cin>>fa>>score[i];
28         son[fa].push_back(i);
29     }
30     memset(f,-1,sizeof(f));
31     search(0);
32     cout<<f[0][m]<<endl; 
33     return 0;
34 }

 

 

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 #include<set>
 8 #include<map>
 9 #include<stack>
10 #include<vector>
11 using namespace std;
12 const int maxn=3007;
13 const int INF=0x7f7f7f7f;
14 int n,m,num;
15 int val[maxn],head[maxn],f[maxn][maxn],sz[maxn];
16 struct Edge{
17   int nxt,to,dis;
18 }edge[maxn];
19 void add(int from,int to,int dis){
20   edge[++num].nxt=head[from];
21   edge[num].to=to;
22   edge[num].dis=dis;
23   head[from]=num;
24 }
25 /*void dfs(int x){
26   f[x][0]=0;
27   if(x>n-m) {f[x][1]=val[x];return;}
28   for(int i=head[x];i;i=edge[i].nxt){
29     int v=edge[i].to;dfs(v);
30     //for(int j=0;j<=sz[x];j++)
31     //  for(int k=0;k<=sz[v];k++)
32     //    {f[x][j]=max(f[x][j],f[v][k]+f[x][j-k]-edge[i].dis);cout<<x<<" "<<j<<" "<<f[x][j]<<endl;} 
33     for(int j=sz[x];j>=0;j--){
34       for(int k=0;k<=j;k++){
35         f[x][j]=max(f[x][j],f[v][k]+f[x][j-k]-edge[i].dis);
36         //cout<<x<<" "<<j<<" "<<f[x][j]<<endl; 
37       }
38     }
39   } 
40 } */
41 int dfs(int x){
42   f[x][0]=0;
43   if(x>n-m){f[x][1]=val[x];return 1;}
44   int tot=0;
45   for(int i=head[x];i;i=edge[i].nxt){
46     int v=edge[i].to;
47     tot+=dfs(v);
48     for(int j=tot;j>=0;j--)//防止一棵子树重复选 
49       for(int k=0;k<=j;k++)
50         f[x][j]=max(f[x][j],f[v][k]+f[x][j-k]-edge[i].dis);
51   }
52   return tot;
53 }
54 int main(){
55   cin>>n>>m;memset(f,-INF,sizeof(f)); 
56   for(int i=1;i<=n-m;i++){
57     cin>>sz[i];
58     for(int j=1;j<=sz[i];j++){
59       int a,c;cin>>a>>c;
60       add(i,a,c);
61     }
62   }
63   for(int i=n-m+1;i<=n;i++) cin>>val[i];
64   dfs(1);
65   for(int i=m;i>=0;i--){
66     if(f[1][i]>=0){cout<<i<<endl;return 0;}
67   }
68 }

 

posted @ 2018-10-24 11:00  lcan  阅读(198)  评论(0编辑  收藏  举报