1. 程式人生 > >規劃 洛谷p1642

規劃 洛谷p1642

題目描述

某地方有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;
}