問題 P(1701): 貪吃的九頭龍
時間限制: 2 Sec 內存限制: 128 MB提交: 57 解決: 22
[提交][狀態][我的提交]
題目描述
傳說中的九頭龍是一種特別貪吃的動物。雖然名字叫“九頭龍”,但這只是說它出生的時候有九個頭,而在成長的過程中,它有時會長出很多的新頭,頭的總數會遠大於九,當然也會有舊頭因衰老而自己脫落。
有一天,有M個腦袋的九頭龍看到一棵長有N個果子的果樹,喜出望外,恨不得一口把它全部吃掉。可是必須照顧到每個頭,因此它需要把N個果子分成M組,每組至少有一個果子,讓每個頭吃一組。
這M個腦袋中有一個最大,稱爲“大頭”,是衆頭之首,它要吃掉恰好K個果子,而且K個果子中理所當然地應該包括唯一的一個最大的果子。果子由N-1根樹枝連接起來,由於果樹是一個整體,因此可以從任意一個果子出發沿着樹枝“走到”任何一個其他的果子。
對於每段樹枝,如果它所連接的兩個果子需要由不同的頭來吃掉,那麼兩個頭會共同把樹枝弄斷而把果子分開;如果這兩個果子是由同一個頭來吃掉,那麼這個頭會懶得把它弄斷而直接把果子連同樹枝一起吃掉。當然,吃樹枝並不是很舒服的,因此每段樹枝都有一個吃下去的“難受值”,而九頭龍的難受值就是所有頭吃掉的樹枝的“難受值”之和。
九頭龍希望它的“難受值”儘量小,你能幫它算算嗎?
例如圖1所示的例子中,果樹包含8個果子,7段樹枝,各段樹枝的“難受值”標記在了樹枝的旁邊。九頭龍有兩個腦袋,大頭需要吃掉4個果子,其中必須包含最大的果子。即N=8,M=2,K=4:
輸入
【輸入文件】
輸入文件dragon.in的第1行包含三個整數N (1<=N<=300),M (2<=M<=N),K (1<=K<=N)。 N個果子依次編號1,2,...,N,且最大的果子的編號總是1。第2行到第N行描述了果樹的形態,每行包含三個整數a (1<=a<=N),b (1<=b<=N),c (0<=c<=105),表示存在一段難受值爲c的樹枝連接果子a和果子b。
輸出
【輸出文件】
輸出文件dragon.out僅有一行,包含一個整數,表示在滿足“大頭”的要求的前提下,九頭龍的難受值的最小值。如果無法滿足要求,輸出-1。
樣例輸入
(如果複製到控制檯無換行,可以先粘貼到文本編輯器,再複製)
8 2 4
1 2 20
1 3 4
1 4 13
2 5 10
2 6 12
3 7 15
3 8 5
樣例輸出
4
提示
樣例對應於題目描述中的例子。
分析:首先,最近嫌疑人x的獻身上映~\(≧▽≦)/~啦啦啦,然後雖然我沒有時間看,但看到這道題時瞬間想到了石神再監獄裏證明四色原理(23333333),然後差不多可以想象,這棵樹中,沒有三個節點互相相鄰的情況,所以一定可以用兩種顏色給樹染色,讓相鄰的節點顏色各不同,所以當m>2時只需要考慮大頭吃k個果子的消耗,(剩下的小頭此時>=2,一定可以0消耗吃完所有果子,就是用兩種顏色給樹染色,讓相鄰的節點顏色各不同)m=1時答案爲w的和,重點在m=2時,(卡了我好久233333~QnQ~)其實也差不多,m>2時只有父親被大頭吃了,他也被大頭吃了時才加當前代價,而m=2,時父親被大頭吃了,他也被大頭吃了和父親沒有被大頭吃,他也沒有被大頭吃兩種情況都要加上當前代價。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<stack>
#include<algorithm>
#include<vector>
using namespace std;
const int N=300+10;
const int inf=0x3f3f3f3f;
struct bian{
int v,w,next;
}arr[N<<1];
struct node{
int l,r;
}tree[N];
void getint(int&num){
char c;int flag=1;num=0;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
num*=flag;
}
int n,m,p,cnt,a,b,w,all,fir[N],A[N],son[N],dp[N][N][2];
bool vis[N][N][2];
void link(int a,int b,int w){
arr[++cnt].v=a,arr[cnt].w=w;
arr[cnt].next=fir[b],fir[b]=cnt;
}
void build(int x,int pre){
int now=0;
for(int i=fir[x];i;i=arr[i].next)
if(arr[i].v!=pre){
A[arr[i].v]=arr[i].w,build(arr[i].v,x);
if(!tree[x].l) tree[x].l=arr[i].v,now=arr[i].v;
else tree[now].r=arr[i].v,now=arr[i].v;
}
}
void Son(int x){
if(!x) return ;
Son(tree[x].l),Son(tree[x].r);
son[x]=son[tree[x].l]+son[tree[x].r]+1;
}
void dfs(int x,int k,bool flag){
if(vis[x][k][flag]) return ;
vis[x][k][flag]=1;
int tmp=inf,add=0;
if(flag) add+=A[x];
if(!k||!x){dp[x][k][flag]=0;return ;}
if(k==1){
if(flag) tmp=min(tmp,A[x]);
else tmp=0;
}
if(!tree[x].l&&!tree[x].r);
else if(!tree[x].l){
if(son[tree[x].r]>=k){
dfs(tree[x].r,k,flag);
tmp=min(tmp,dp[tree[x].r][k][flag]);
}
if(son[tree[x].r]>=k-1){
dfs(tree[x].r,k-1,flag);
tmp=min(tmp,dp[tree[x].r][k-1][flag]+add);
}
}
else if(!tree[x].r){
if(son[tree[x].l]>=k){
dfs(tree[x].l,k,0);
tmp=min(tmp,dp[tree[x].l][k][0]);
}
if(son[tree[x].l]>=k-1){
dfs(tree[x].l,k-1,1);
tmp=min(tmp,dp[tree[x].l][k-1][1]+add);
}
}
else{
for(int i=0;i<=k;i++){
if(son[tree[x].l]<i||son[tree[x].r]<k-i) continue ;
dfs(tree[x].l,i,0);
dfs(tree[x].r,k-i,flag);
tmp=min(tmp,dp[tree[x].l][i][0]+dp[tree[x].r][k-i][flag]);
}
for(int i=1;i<=k;i++){
if(son[tree[x].l]<i-1||son[tree[x].r]<k-i) continue ;
dfs(tree[x].l,i-1,1);
dfs(tree[x].r,k-i,flag);
tmp=min(tmp,dp[tree[x].l][i-1][1]+dp[tree[x].r][k-i][flag]+add);
}
}
dp[x][k][flag]=tmp;
}
void work(int x,int k,int flag)
{
if(vis[x][k][flag]) return ;
vis[x][k][flag]=1;
if(!x&&k){dp[x][k][flag]=inf;return ;}
if(!x&&!k){dp[x][k][flag]=0;return ;}
int tmp=inf,add=0;
if(flag==0) add=A[x];else add=0;
for(int i=0;i<=k;i++){
work(tree[x].l,i,0),work(tree[x].r,k-i,flag);
tmp=min(tmp,add+dp[tree[x].l][i][0]+dp[tree[x].r][k-i][flag]);
}
if(flag==1) add=A[x];else add=0;
for(int i=0;i<k;i++){
work(tree[x].l,i,1),work(tree[x].r,k-i-1,flag);
tmp=min(tmp,add+dp[tree[x].l][i][1]+dp[tree[x].r][k-i-1][flag]);
}
dp[x][k][flag]=tmp;
}
int main(){
getint(n),getint(m),getint(p);
if(n-p<m-1){
printf("-1\n");return 0;
}
for(int i=1;i<n;i++){
getint(a),getint(b),getint(w);
link(a,b,w),link(b,a,w),all+=w;
}
if(m==1){
printf("%d\n",all);return 0;
}
build(1,-1),Son(1);
if(m==2){
work(tree[1].l,p-1,1);
printf("%d\n",dp[tree[1].l][p-1][1]);
}
else{
dfs(tree[1].l,p-1,1);
printf("%d\n",dp[tree[1].l][p-1][1]);
}
}