NKOI 3695 清洁机器人

来源:互联网 发布:免费手机数据恢复软件 编辑:程序博客网 时间:2024/04/25 18:52
                                                    P3695清洁机器人
                                                       Time Limit : 1000MS   Memory Limit : 65536 KB  
Description
NK中学有n间教室(编号1到n),通过n-1条双向道路相连,每条道路的长度可能不同。现在有k台清洁机器人位于s号教室,现在要安排它们去清洁所有教室。
机器人靠燃油驱动,一台机器人清洁一个教室的耗油1升。在道路上行走时,每单位距离耗油1L。
我们希望完成清洁作业消耗的总油量尽可能少。请你计算出这个总油量。
作业结束时,机器人可以停留在任何位置。

Input Format
第一行,三个整数n,s,k
接下来n-1行,每行三个整数a,b,c,表示教室a和教室b之间有条长度为c的道路相连。

Output Format
一行,一个整数,表示所求答案。
Sample Input 1
3 1 1
1 2 1
1 3 1
Sample Output 1
6
Sample Input 2
3 1 2
1 2 1
1 3 1
Sample Output 2
5
Hint
样例1说明,机器人的活动线路为1->2->1->3,路上耗费3L燃油,清洁教室耗费3L
1<=n<=10000, 1<=s<=N, 1<=k<=10

1<=c<=1000000.


设定状态:状态dp[u][j]为以u为根的子树,结束时有j个机器人留在了该子树中,所有机器人走的距离之和的最小值。

状态转移分析:

1.没有机器人留在该子树中:dp[u][0]= ∑(dp[v][0]+2*Len[u][v])其中V为u的儿子节点,Len[u][v]表示u到儿子v的边长。最终所有机器人都离开了u为根的子树,故该子树每条边都被经过了2次。

2.有机器人留在子树中:dp[u][j]=min(dp[u][j−t]+dp[v][t]+t*Len[u][v])   0≤t≤j  ,  0≤j≤K

其中dp[v][t]表示将t个机器人分配给v号儿子,因此u点还剩下j-t个儿子

由于dp[v][t]+dp[u][j-t]中并没有包含从u走到v的边的消耗量,由于走了t个机器人,所以要加上t*len[u][v]

#include<cstdio>#include<iostream>using namespace std;const int maxn=10005;int n,s,k,cnt;long long f[maxn][13];int LEN[2*maxn],NEXT[2*maxn],LAST[maxn],END[2*maxn];void insert(int a,int b,int l){      END[++cnt]=b;      LEN[cnt]=l;      NEXT[cnt]=LAST[a];      LAST[a]=cnt;  }void dp(int u,int fa){int i,j,t,q,v;for(i=LAST[u],v=END[i];i;i=NEXT[i],v=END[i]){if(v==fa)continue;dp(v,u);for(j=k;j>=0;j--){//j要逆序枚举,想一想为什么f[u][j]+=f[v][0]+2*LEN[i];             ////////相当于f赋值为无穷大,最后当j等于0就是之前讨论的p[u][0]=∑(dp[v][0]+2*Len[u][v])for(t=0;t<=j;t++)    f[u][j]=min(f[u][j],f[v][t]+f[u][j-t]+t*LEN[i]);}}}int main(){scanf("%d%d%d",&n,&s,&k);int i,j,x,y,z;for(i=1;i<n;i++){scanf("%d%d%d",&x,&y,&z);insert(x,y,z);insert(y,x,z);}dp(s,-1);cout<<f[s][k]+n;//f数组只讨论了边,最后要加上n个教室的消耗}


0 0