题目描述
某地方有N个工厂,有N-1条路连接它们,且它们两两都可达。每个工厂都有一个产量值和一个污染值。现在工厂要进行规划,拆除其中的M个工厂,使得剩下的工厂依然连成一片且 总产量/总污染 的值最大。
输入输出格式
输入格式:
第一行N M(1<N<100,1<=M<N),表示工厂个数和要拆除的个数。
第二行N个正整数,表示每个工厂的产值[1..10000]
第三行N个正整数,表示每个工厂的污染值[1..10000]
接着N-1行,每行两个正整数a b(1<=a,b<=N)表示a,b之间相连。
输出格式:
总产量/总污染 的最大值,保留一位小数。
输入输出样例
输入样例#1: 复制
3 2 2 3 4 1 1 1 1 2 2 3
输出样例#1: 复制
4.0
题解:01分数规划二分答案,树形dp求包含(n-m)个节点的最大子树和。
#include<bits/stdc++.h>
#define f(i,l,r) for(i=(l);i<=(r);i++)
#define ff(i,r,l) for(i=(r);i>=(l);i--)
using namespace std;
const int MAXN=105,INF=1e20;
double EPS=1e-3;
struct Node{
int v,w;
double c;
}a[MAXN];
struct Edge{
int v,nxt;
}e[MAXN<<1];
int n,m;
double f[MAXN][MAXN];
int h[MAXN],tot,size[MAXN],flag;
inline void add(int u,int v)
{
e[tot].v=v;
e[tot].nxt=h[u];
h[u]=tot++;
}
void dfs(int u,int fa)
{
int i,j,k;
size[u]=1;
f[u][1]=a[u].c;
for(i=h[u];~i;i=e[i].nxt){
int v=e[i].v;
if(v==fa) continue;
dfs(v,u);
if(flag) return;
size[u]+=size[v];
int max_j=min(n-m,size[u]);
ff(j,max_j,2){
f(k,1,j-1){
f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]);
}
}
}
if(f[u][n-m]>=0){
flag=1;
}
}
bool check(double ans)
{
int i,j;
f(i,1,n){
a[i].c=1.0*a[i].v-ans*a[i].w;
}
f(i,1,n){
f(j,1,n){
f[i][j]=-INF;
}
}
flag=0;
dfs(1,-1);
return flag;
}
int main()
{
ios::sync_with_stdio(false);
memset(h,-1,sizeof(h));
int i,j,u,v;
double l=0,r=10000;
cin>>n>>m;
f(i,1,n){
cin>>a[i].v;
}
f(i,1,n){
cin>>a[i].w;
}
f(i,1,n-1){
cin>>u>>v;
add(u,v);
add(v,u);
}
while(r-l>EPS){
double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
cout<<fixed<<setprecision(1)<<l<<endl;
return 0;
}