Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 3309 | Accepted: 1703 |
Description
Input
Output
Sample Input
9 6 3 2 2 3 2 9 3 2 4 2 5 2 3 6 2 7 2 8 2 4 3 3 3 1 1
Sample Output
5
题目描述:
有一个电视台要用电视网络转播节目。这种电视网络是一树,树的节点为中转站或者用户。树节点的编号为1~N,其中1为总站,2~(N-M)为中转站,(总站和中转站统称为转发站)N-M+1~N为用户,电视节目从一个地方传到另一个地方都要费用,同时每一个用户愿意出相应的钱来付电视节目。现在的问题是,在电视台不亏本的前提下,要你求最多允许有多少个用户可以看到电视节目。
输入:
N M N表示转发站和用户总数,M为用户数
以下N-M行,第i行第一个K,表示转发站i和K个(转发站或用户)相连, 其后第j对数val,cost表示,第i个转发站到val有边,费用cost.
最后一行M个数表示每个用户愿意负的钱。
输出:
不亏本前提下,可以收到节目最多的用户数。
(如果某个用户要收到节目(叶子结点),那么电视台到该用户的路径节点的费用都要付)
思路:在树上进行背包,对于以u为根的子树,该子树供给给j个用户亏本的最少钱#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <queue> #include <algorithm> #include <map> #include <iomanip> #define INF 99999999 typedef long long LL; using namespace std; const int MAX=3000+10; int head[MAX],size,n,m; int val[MAX],dp[MAX][MAX];//dp记录以u为根的子树供给j个用户亏损的最少钱 struct Edge{ int v,w,next; Edge(){} Edge(int V,int W,int NEXT):v(V),w(W),next(NEXT){} }edge[MAX*2]; void Init(int num){ for(int i=1;i<=num;++i){ head[i]=-1; for(int j=1;j<=num;++j)dp[i][j]=INF; } size=0; } void InsertEdge(int u,int v,int w){ edge[size]=Edge(v,w,head[u]); head[u]=size++; } int dfs(int u,int father){ int ans=0,p,now; for(int i=head[u];i != -1;i=edge[i].next){ int v=edge[i].v,w=edge[i].w; if(v == father)continue; now=dfs(v,u); if(v>=n-m+1)++now,p=1; else p=0; ans+=now; for(int j=min(m,ans);j>=1;--j){//这里注意一定要j=min(m,ans),复杂度为O(n^3)=>接近O(n^2) for(int k=min(j,now);k>=1;--k){//以u为根的子树供给给j个用户并且有k个用户属于v为根的子树时亏损的最少钱 dp[u][j]=min(dp[u][j],dp[u][j-k]+dp[v][k-p]+w-val[v]); } } } return ans; } int main(){ int k,v,w; while(~scanf("%d%d",&n,&m)){ Init(n); for(int i=1;i<=n-m;++i){ scanf("%d",&k); val[i]=0; for(int j=1;j<=k;++j){ scanf("%d%d",&v,&w); InsertEdge(i,v,w); InsertEdge(v,i,w); } } for(int i=n-m+1;i<=n;++i)scanf("%d",&val[i]); dfs(1,-1); int sum=0; for(n=1;n<=m;++n)if(dp[1][n]<=0)sum=n; printf("%d\n",sum); } return 0; }