/**//* 题意:给出一棵树,总时间P,经过a-b时间为c,在每个点观光时间为x 现有Q个x,问对应每个x在P时间内能观光的最多点的个数 n<=200 p<=1000000
之前想的背包,以时间作为容量的,肯定不行 看了这里,发现我思维定势了,应该是以经过多少个点作为容量O(n^3) http://xpycc.blog.163.com/blog/static/50266902201072910757650/
状态的设计,我也是第一次遇到这样子的,poj 2486有一道简化版的
f0[u]表示起点、终点都不在u f1[u]表示一个点在u f2[u]表示起点、终点都在u
转移时,主要是注意f0[u] 那起点、终点可以是之前的,或者一个之前一个当前,或者两个都是当前
最后的答案,很神奇的,按照上面表示的话就能直接是: x*tot + dp[tot] */ #include<cstdio> #include<cstring> #include<algorithm> #include<vector>
using namespace std;
const int MAXN = 250; const int INF = 1000000000;
vector<pair<int,int> > E[MAXN]; int f0[MAXN][MAXN] , f1[MAXN][MAXN] , f2[MAXN][MAXN] , f3[MAXN][MAXN]; int dp[MAXN]; int size[MAXN];
void dfs(int u , int p) { size[u] = 1; for(vector<pair<int,int> >::iterator it = E[u].begin() ; it != E[u].end() ; it++) { int v = it->first; if(v == p )continue; dfs(v , u); size[u] += size[v]; }
for(int j = 1 ; j <= size[u]; j ++) f0[u][j] = f1[u][j] = f2[u][j] = INF; f0[u][1] = f1[u][1] = f2[u][1] = 0; for(vector<pair<int,int> >::iterator it = E[u].begin() ; it != E[u].end() ; it++) { int v = it->first , w = it->second; if( v == p )continue; for(int j = size[u]; j > 1 ; j --) for(int k = 1 ; k < j && k <= size[v] ; k++) { //root -> x -> root f2[u][j] = min(f2[u][j] , f2[u][j-k] + f2[v][k] + 2*w);
//root -> x , x -> root f1[u][j] = min(f1[u][j] , f2[u][j-k] + f1[v][k] + w); f1[u][j] = min(f1[u][j] , f1[u][j-k] + f2[v][k] + 2*w);
// x -> root -> x f0[u][j] = min(f0[u][j] , f0[u][j-k] + f2[v][k] + 2*w); f0[u][j] = min(f0[u][j] , f1[u][j-k] + f1[v][k] + w); f0[u][j] = min(f0[u][j] , f2[u][j-k] + f0[v][k] + 2*w); } } for(int j = 1; j <= size[u] ; j++) { f3[u][j] = min(f0[u][j] , f1[u][j]); f3[u][j] = min(f3[u][j] , f2[u][j]); dp[j] = min(dp[j],f3[u][j]); } }
int main() { #ifdef ONLINE_JUDGE #else freopen("in","r",stdin); #endif int T , t = 1; for(scanf("%d",&T) ; T-- ; ) { int n,p; scanf("%d%d",&n,&p); for(int i = 1 ; i <= n; i++) { E[i].clear(); } int a , b , c; for(int i = 1 ; i < n ; i++) { scanf("%d%d%d",&a,&b,&c); E[a].push_back(make_pair(b,c)); E[b].push_back(make_pair(a,c)); }
dp[0] = 0; fill(dp+1,dp+n+1,INF); dfs(1,1); printf("Case %d:\n",t++); int Q , x; for(scanf("%d",&Q) ; Q--;) { scanf("%d",&x); int tot ; for(tot = 0; tot <= n ; tot++) { if( tot*x + dp[tot] > p)break; } printf("%d\n",--tot); } } return 0; }
|
|
常用链接
随笔分类
Links
搜索
最新评论
|
|