当前位置:网站首页>有线电视网(树上分组)
有线电视网(树上分组)
2022-07-17 05:13:00 【lovesickman】
P1273 有线电视网
题目描述
某收费有线电视网计划转播一场重要的足球比赛。他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节点。
从转播站到转播站以及从转播站到所有用户终端的信号传输费用都是已知的,一场转播的总费用等于传输信号的费用总和。
现在每个用户都准备了一笔费用想观看这场精彩的足球比赛,有线电视网有权决定给哪些用户提供信号而不给哪些用户提供信号。
写一个程序找出一个方案使得有线电视网在不亏本的情况下使观看转播的用户尽可能多。
输入格式
输入文件的第一行包含两个用空格隔开的整数 N N N 和 M M M,其中 2 ≤ N ≤ 3000 2 \le N \le 3000 2≤N≤3000, 1 ≤ M ≤ N − 1 1 \le M \le N-1 1≤M≤N−1, N N N 为整个有线电视网的结点总数, M M M 为用户终端的数量。
第一个转播站即树的根结点编号为 1 1 1,其他的转播站编号为 2 2 2 到 N − M N-M N−M,用户终端编号为 N − M + 1 N-M+1 N−M+1 到 N N N。
接下来的 N − M N-M N−M 行每行表示—个转播站的数据,第 i + 1 i+1 i+1 行表示第 i i i 个转播站的数据,其格式如下:
K A 1 C 1 A 2 C 2 … A k C k K \ \ A_1 \ \ C_1 \ \ A_2 \ \ C_2 \ \ \ldots \ \ A_k \ \ C_k K A1 C1 A2 C2 … Ak Ck
K K K 表示该转播站下接 K K K 个结点(转播站或用户),每个结点对应一对整数 A A A 与 C C C , A A A 表示结点编号, C C C 表示从当前转播站传输信号到结点 A A A 的费用。最后一行依次表示所有用户为观看比赛而准备支付的钱数。单次传输成本和用户愿意交的费用均不超过 10。
输出格式
输出文件仅一行,包含一个整数,表示上述问题所要求的最大用户数。
样例 #1
样例输入 #1
5 3
2 2 2 5 3
2 3 2 4 3
3 4 2
样例输出 #1
2
提示
样例解释
如图所示,共有五个结点。结点 ① 为根结点,即现场直播站,② 为一个中转站,③④⑤ 为用户端,共 M M M 个,编号从 N − M + 1 N-M+1 N−M+1 到 N N N,他们为观看比赛分别准备的钱数为 3 3 3、 4 4 4、 2 2 2。
从结点 ① 可以传送信号到结点 ②,费用为 2 2 2;
也可以传送信号到结点 ⑤,费用为 3 3 3(第二行数据所示);
从结点 ② 可以传输信号到结点 ③,费用为 2 2 2;
也可传输信号到结点 ④,费用为 3 3 3(第三行数据所示)。
如果要让所有用户(③④⑤)都能看上比赛,则信号传输的总费用为: 2 + 3 + 2 + 3 = 10 2+3+2+3=10 2+3+2+3=10,大于用户愿意支付的总费用 3 + 4 + 2 = 9 3+4+2=9 3+4+2=9,有线电视网就亏本了,而只让 ③④ 两个用户看比赛就不亏本了。
模仿着带依赖的背包写的,有种说不出来的奇怪,可能是初始化是错的?
f [ u ] [ j ] f[u][j] f[u][j] 表示以 u u u 为根节点,花费 j j j 所能得到的最大用户的数量。
int n,m,son;
int h[3110],e[3110*2],ne[3110*2],idx,w[3110*2];
int money[3110];
int f[3110][31110];// f[u][j] 表示 u 为根的子树花费 j 取得的最大值
void add(int a,int b,int c){
e[idx]=b;
ne[idx]=h[a];
w[idx]=c;
h[a]=idx++;
}
void dfs(int u,int fa,int cost){
bool flag = 0;
for(int i=h[u];~i;i=ne[i]){
int j=e[i],Cost=w[i];
if(j==fa)continue;
debug(j);
debug(Cost);
flag = 1;
dfs(j,u,cost+Cost);
for(int k=m;k>=cost;k--){
for(int l=0;l<=k-cost;l++){
f[u][k] = max(f[u][k],f[u][k-l]+f[j][l]);
}
}
}
if(!flag){
//叶子节点
for(int k=m;k>=cost;k--){
if(k<=money[u]){
f[u][k] = 1;
}
}
}
}
void solve(){
memset(h,-1,sizeof(h));
cin>>n>>son;
for(int i=1;i<=n-son;i++){
int k;cin>>k;
fo(j,1,k){
int id,cost;cin>>id>>cost;
cout<<i<<" "<<id<<" "<<cost<<endl;
add(i,id,cost);
add(id,i,cost);
m+=cost;
}
}
for(int i=n-son+1;i<=n;i++){
int cost;cin>>cost;
money[i]=cost;
}
dfs(1,-1,0);
cout<<f[1][m]<<endl;
}
int main(){
solve();
return 0;
}
看了题解之后,人都不好了。
题解一般是定义成 f [ u ] [ j ] f[u][j] f[u][j] 表示以 u u u 为根节点,满足 j j j 个客户(叶子)所能获得的最大收益。
枚举 i i i ,找到最大的 f [ 1 ] [ i ] ≥ 0 f[1][i] \ge0 f[1][i]≥0 。
好有道理的样子
又TM陷入SB找不同了。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <assert.h>
#include <sstream>
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define mem(f, x) memset(f,x,sizeof(f))
#define fo(i,a,n) for(int i=(a);i<=(n);++i)
#define fo_(i,a,n) for(int i=(a);i<(n);++i)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'
using namespace std;
//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math,O3")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
template<typename T>
ostream& operator<<(ostream& os,const vector<T>&v){
for(int i=0,j=0;i<v.size();i++,j++)if(j>=5){
j=0;puts("");}else os<<v[i]<<" ";return os;}
template<typename T>
ostream& operator<<(ostream& os,const set<T>&v){
for(auto c:v)os<<c<<" ";return os;}
template<typename T1,typename T2>
ostream& operator<<(ostream& os,const map<T1,T2>&v){
for(auto c:v)os<<c.first<<" "<<c.second<<endl;return os;}
template<typename T>inline void rd(T &a) {
char c = getchar(); T x = 0, f = 1; while (!isdigit(c)) {
if (c == '-')f = -1; c = getchar();}
while (isdigit(c)) {
x = (x << 1) + (x << 3) + c - '0'; c = getchar();} a = f * x;
}
typedef pair<long long ,long long >PII;
typedef pair<long,long>PLL;
typedef long long ll;
typedef unsigned long long ull;
const int N=2e5+10,M=1e9+7;
int n,son;
int h[3110],e[3110*2],ne[3110*2],idx,w[3110*2];
int money[3110];
int f[3110][3110];// f[u][j] 表示 u 为根的子树选取 j 个儿子盈利的最大值
void add(int a,int b,int c){
e[idx]=b;
ne[idx]=h[a];
w[idx]=c;
h[a]=idx++;
}
int dfs(int u,int fa){
// 返回以u为根的子树中含有的叶子节点的个数
if(u>n-son){
f[u][1] = money[u];
return 1;
}
int sum=0,t;
for(int i=h[u];~i;i=ne[i]){
if(e[i]==fa)continue;
t = dfs(e[i],u);
int cost = w[i];
sum+=t;
// cout<<endl;
// debug(u);
// debug(sum);
// cout<<endl;
/* 树上分组背包 1:遍历组 2:遍历体积 3:遍历决策 */
// cout<<u<<" "<<t<<endl;
for(int j=sum;j>0;j--){
for(int I=1;I<=t;I++){
if(j>=I){
cout<<cost<<endl;
f[u][j]=max(f[u][j],f[u][j-I]+f[j][I]-cost);
cout<<" "<<f[u][j]<<endl;
}
}
}
}
// cout<<u<<" "<<sum<<endl;
return sum;
}
void solve(){
memset(h,-1,sizeof(h));
memset(f,~0x3f,sizeof f);
cin>>n>>son;
for(int i=1;i<=n-son;i++){
int k;cin>>k;
fo(j,1,k){
int id,cost;cin>>id>>cost;
add(i,id,cost);
add(id,i,cost);
}
}
for(int i=n-son+1;i<=n;i++){
int cost;cin>>cost;
money[i]=cost;
}
for(int i=1;i<=n;i++)f[i][0]=0;
dfs(1,-1);
for(int i=son;i>=0;i--){
debug(f[1][i]);
if(f[1][i]>=0){
cout<<i<<endl;
return ;
}
}
}
int main(){
solve();
return 0;
}
破案了!
f[u][j]=max(f[u][j],f[u][j-I]+f[j][I]-cost);
应该是
f[u][j]=max(f[u][j],f[u][j-I]+f[e[i]][I]-cost);
变量多了,我就是猪脑子
int n,m;
int h[3110],e[3110*2],ne[3110*2],idx,w[3110*2];
int money[3110];
int f[3110][3110];// f[u][j] 表示 u 为根的子树选取 j 个儿子盈利的最大值
void add(int a,int b,int c){
e[idx]=b;
ne[idx]=h[a];
w[idx]=c;
h[a]=idx++;
}
int dfs(int u,int fa){
// 返回以u为根的子树中含有的叶子节点的个数
if(u>n-m){
f[u][1] = money[u];
return 1;
}
int sum=0,t;
for(int i=h[u];~i;i=ne[i]){
// 遍历组
if(e[i]==fa)continue;
t = dfs(e[i],u);
int cost = w[i];
int next = e[i];
sum+=t;
/* 树上分组背包 1:遍历组 2:遍历体积 3:遍历决策 */
for(int j=sum;j>0;j--){
// 遍历体积,以u为根的子树的儿子节点的数目
for(int i=1;i<=t;i++){
// 决策,这个分叉选多少个叶节点
if(j>=i){
f[u][j]=max(f[u][j],f[u][j-i]+f[next][i]-cost);
}
}
}
}
return sum;
}
void solve(){
memset(h,-1,sizeof(h));
memset(f,~0x3f,sizeof f);
cin>>n>>m;
for(int i=1;i<=n-m;i++){
int k;cin>>k;
fo(j,1,k){
int id,cost;cin>>id>>cost;
add(i,id,cost);
}
}
for(int i=n-m+1;i<=n;i++){
cin>>money[i];
}
for(int i=1;i<=n;i++)f[i][0]=0;
dfs(1,-1);
for(int i=m;i>=0;i--){
if(f[1][i]>=0){
cout<<i<<endl;
return ;
}
}
}
int main(){
solve();
return 0;
}
边栏推荐
- Digital signal isolation module adum1401arwz yadeno in stock
- 单片机的好搭档-CS创世SD NAND FLASH
- 2021-11-10 micropyton TB6600步进驱动类
- 压力应变桥信号处理光电隔离放大器
- 软考初、中、高级考试全体验
- Vscode instant English translation plug-in [translation (English Chinese Dictionary)]
- Unable to determine Electron version. Please specify an Electron version
- 本地makefile 编译其他文件夹文件 指定obj目录
- 隔离4-20mA或0-20mA信号传输
- 设置索引库结构,给用户添加可自动补全的suggestion,并将一些字段变成集合放到suggestion里面去
猜你喜欢
Proportional valve amplifier 1a, 2a, 3a, 5A proportional valve drive module 0-10V to 0-24v
Vscode instant English translation plug-in [translation (English Chinese Dictionary)]
3.7V lithium battery boost to 5v1a, fs2114 boost conversion chip design layout
go语言介绍及应用场景分析
RestClient查询文档
设置索引库结构,给用户添加可自动补全的suggestion,并将一些字段变成集合放到suggestion里面去
LTH7五脚芯片的完整方案图FS4054充电电路原理
High voltage module isolation module hra2460d-2w
Digital signal isolation module adum1401arwz yadeno in stock
4-channel encoder pulse counter, 8-Channel do, Modbus TCP module
随机推荐
ES聚合分析报错:“reason“ : “Text fields are not optimised for operations
获取当前年月日、时分秒、星期,并实时更新
LTH7五脚芯片的完整方案图FS4054充电电路原理
vscode 配置golang开发环境
4 路 FMC+基带信号处理板( 4 路 2G 瞬时带宽 AD+DA)
HRA 1~12W 系列12V《宽压9~18V》转±250VDC等升压变换器
Complete scheme diagram of lth7 five pin chip fs4054 charging circuit principle
什么是tSD/qSD?CS创世 SD NAND到底是什么?
HRA2460D-2w高压电源高压模块-高压---高精度hra2460d-2w
BusyBox 1.21.1 有udpsvd功能 可以编译成功 不干涉本机busybox方法
解决:无法加载文件 C:\Program Files\.. 因为在此系统上禁止运行脚本...
busybox date 日期增加一天明天 网上都是减一天 昨天
分享CS品牌贴片式T卡在打猎相机领域的运用案例
Review of software process and management (IX)
QTSS回调例程
带透明png转换成c数组
minio安装部署及简单使用
c语言 指定日期开始多少天 显示
升高压模块隔离模块HRA2460D-2W
Hm9922 switching buck LED constant current driver IC