Find Metal Mineral
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Others)Total Submission(s): 3474 Accepted Submission(s): 1615
In each case:
The first line specifies three integers N, S, K specifying the numbers of metal mineral, landing site and the number of robots.
The next n‐1 lines will give three integers x, y, w in each line specifying there is a path connected point x and y which should cost w.
1<=N<=10000, 1<=S<=N, 1<=k<=10, 1<=x, y<=N, 1<=w<=10000.
3 1 1 1 2 1 1 3 1 3 1 2 1 2 1 1 3 1
3 2HintIn the first case: 1->2->1->3 the cost is 3;In the second case: 1->2; 1->3 the cost is 2;
2016年亚洲赛大连站热身赛,当时没有做出来,尴尬,
题意是给一棵树,给一个起点S ,k个机器人,每个机器人只能从起点S出发,最终要使所有点被遍历到,每两个节点之间有一个花费,求出最小的总花费
显然是一个树形dp,
思路:这是我从别人博客里找到的解释,因为很详细就引用了
dp[i][j]表示对于以i结点为根结点的子树,放j个机器人所需要的权值和。
当j=0时表示放了一个机器人下去,遍历完结点后又回到i结点了。状态转移方程类似背包
如果最终的状态中以i为根结点的树中有j(j>0)个机器人,那么不可能有别的机器人r到了这棵树后又跑到别的树中去
因为那样的话,一定会比j中的某一个到达i后跑与r相同的路径再回到i,再接着跑它的路径要差(多了一条i回去的边)
这样的话,如果最后以i为根结点的树中没有机器人,那么只可能是派一个机器人下去遍历完后再回来
可以这么理解:
对于每个根节点root,有个容量为K的背包
如果它有i个儿子,那么就有i组物品,价值分别为dp[son][0],dp[son][1].....dp[son][k] ,这些物品的重量分别为0,1,.....k
现在要求从每组里选一个物品(且必须选一个物品)装进root的背包,使得容量不超过k的情况下价值最大。
那么这就是个分组背包的问题了。
但是这里有一个问题,就是每组必须选一个物品。
对于这个的处理,我们先将dp[son][0]放进背包,如果该组里有更好的选择,那么就会换掉这个物品,否则的话这个物品就是最好的选择。这样保证每组必定选了一个。
#include <iostream> #include <stdio.h> #include <algorithm> #include <string.h> using namespace std; const int maxn =1e6+10; const int inf=0x3f3f3f3f; struct node { int next,v,w; }edge[maxn]; int n,s,k; int dp[100000][15]; int tot,head[maxn]; void init() { tot=0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int w) { edge[tot].v=v; edge[tot].w=w; edge[tot].next=head[u]; head[u]=tot++; } void dfs(int u,int pre) { for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(v==pre) continue; dfs(v,u); for(int j=k;j>=0;j--)///分组背包 { dp[u][j]+=dp[v][0]+2*edge[i].w; for(int l=1;l<=j;l++) { dp[u][j]=min(dp[u][j],dp[u][j-l]+dp[v][l]+l*edge[i].w); } } } } int main() { int u,v,w; while(scanf("%d%d%d",&n,&s,&k)!=-1) { init(); for(int i=1;i<n;i++) { scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); addedge(v,u,w); } memset(dp,0,sizeof(dp)); dfs(s,0); printf("%d\n",dp[s][k]); } //cout << "Hello world!" << endl; return 0; }