时间限制:12000ms
单点时限:1000ms
内存限制:256MB
描述
编织者是 Dota 系列中的一个伪核,拥有很强的生存能力和线上消耗能力。编织者的代表性技能是缩地。缩地带来的隐身、极限移动速度和伤害让它拥有很高的机动性以及赖线和收割的能力。
假设当前作战区域是一棵有根树,编织者所在的位置为根节点1,树中每个节点,有一个权值vi,代表这个节点的收益。树中的每条边,有一个权值wi,代表每条边的长度。编织者从根结点出发,最远累计移动d 距离时,所能得到的收益的最大值是多少?注意重复经过一个节点收益只能计算一次。
输入
第一行包含一个整数 n (1?≤?n?≤?100),表示节点总数。
接下来的一行,包含 n 个数字,表示一个结点的价值 vi(0?≤?vi?≤?2)。
接下来的 n-1 行,每行三个整数 (ai, bi, wi)。表示一条连接 ai, bi 节点的边,边长为 wi (1?≤?ai,?bi?≤?n,?1?≤?wi?≤?104)。
接下来的一行包含一个数 q,表示询问总数 (0?≤?q? ≤?100000)。 接下来 q 行,每行包含一个整数 d (?≤?d? ≤?106),表示从根结点出发,最远累计移动的距离 d 。
输出
对于每组询问,输出一行表示对应的询问所能得到的最大收益。
- 样例输入
-
3 0 1 1 1 2 5 1 3 3 3 3 10 11
- 样例输出
-
1 1 2
简直了,开始把为了方便找错,把200写成20,结果提交后一直wa,200和20又长得怎么像。艾玛啊,咯咯鸡。
注意边界即可,思路及其好想,不多解释。
#include<cstdio> #include<cstdlib> #include<iostream> #include<algorithm> #include<cstring> #include<memory> using namespace std; const int maxn=220; const int inf=1e9; int vis[maxn],n,m; int dp[maxn][maxn][2],V[maxn]; int Laxt[maxn],Next[maxn],To[maxn],dis[maxn],cnt; void _add(int u,int v,int d) { Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; dis[cnt]=d; } int _dfs(int u) { vis[u]=true; for(int i=Laxt[u];i;i=Next[i]){ int v=To[i]; if(vis[v]) continue; _dfs(v); for(int j=200;j>=0;j--) for(int k=j;k>=0;k--){ //此处的边界特殊在可以为j,也可以为0 dp[u][j][1]=min(dp[u][j][1],dp[u][j-k][1]+dp[v][k][1]+2*dis[i]); dp[u][j][0]=min(dp[u][j][0],dp[u][j-k][1]+dp[v][k][0]+dis[i]); dp[u][j][0]=min(dp[u][j][0],dp[u][j-k][0]+dp[v][k][1]+2*dis[i]); } } } int main() { int i,j,u,v,d,q; scanf("%d",&n); for(i=0;i<=100;i++) for(j=0;j<=200;j++) dp[i][j][0]=dp[i][j][1]=inf; for(i=1;i<=n;i++) { scanf("%d",&V[i]); dp[i][V[i]][1]=0; dp[i][V[i]][0]=0; } for(i=1;i<n;i++){ scanf("%d%d%d",&u,&v,&d); _add(u,v,d); _add(v,u,d); } _dfs(1); scanf("%d",&q); while(q--){ scanf("%d",&u); for(i=200;i>=1;i--) if(dp[1][i][0]<=u) break; printf("%d\n",i); } return 0; }
时间: 2024-11-10 16:15:35