3.消息傳遞
【問題描述】
巴蜀國的社會等級森嚴,除了國王之外,每個人均有且隻有一個直接上級,當然國王沒有上級。如果A是B的上級,B是C的上級,那麼A就是C的上級。絕對不會出現這樣的關系:A是B的上級,B也是A的上級。
最開始的時刻是0,你要做的就是用1機關的時間把一個消息告訴某一個人,讓他們自行散布消息。在任意一個時間機關中,任何一個已經接到消息的人,都可以把消息告訴他的一個直接上級或者直接下屬。
現在,你想知道:
1.到底需要多長時間,消息才能傳遍整個巴蜀國的所有人?
2.要使消息在傳遞過程中消耗的時間最短,可供選擇的人有那些?
【檔案輸入】
輸入檔案的第一行為一個整數N(N≤1000),表示巴蜀國人的總數,假如人按照1到n編上了号碼,國王的編号是1。第2行到第N行(共N-1行),每一行一個整數,第i行的整數表示編号為i的人直接上級的編号。
【檔案輸出】
檔案輸出共計兩行:
第一行為一個整數,表示最後一個人接到消息的最早時間。
第二行有若幹個數,表示可供選擇人的編号,按照編号從小到大的順序輸出,中間用空格分開。
【樣例輸入】
8
1
1
3
4
4
4
3
【樣例輸出】
5
3 4 5 6 7
感覺很基礎的一道題,但是沒敢下手,就是卡在了一個點上,父親傳遞給兒子的時候(枚舉每一個點為根節點),每一個的時間是不同的,當時卡在了這一點上,沒有想出解決方案。實際上隻需要一個貪心就夠了,也就是盡早給時間比較久的傳遞,是以(覃禹舜的選排)按降序排序就好了,f[i] = max{f[j]+k}j是i的兒子,k為排序的序号。
一開始的時候考慮的是,求一條直徑,在直徑上找點,但是仔細看題,給每個兒子傳遞的時間是不同的,是以用前序的搜尋是無法解決的,因為傳遞給兒子的順序是要由兒子的時間來決定的,是以這個政策是錯誤的。從這裡啟發寫樹形DP。
這道題再次使用到歐教講過多次的技巧。一棵形狀不确定的樹,不用建出來,隻需要在搜尋的時候用标記變量記錄走過的點,即能實作動态地建一棵樹。這道題同樣,因為從一個點出發,必須走遍其他所有的點(這一點不同于前兩天那一道treedp,因為那一道題可以選擇不走某一棵子樹,是以一次dp就行了,在路上維護ans值),是以必須進行n次dp,每次以i為根,解為f[i]。
讨論了這些這些之後,就沒有多少技巧性的東西,就是一個簡單的treedp。
就是卡在了
qsort(s[l]+1,s[l][0],sizeof(s[1][0]),&bigger);
for (long i=1;i<s[l][0]+1;i++)
{
f[l] >?= s[l][i]+i;
}
這部分上。
有什麼啟示呢?有什麼啟示呢?我遇到瓶頸了。。。感覺這種時候反而更需要打開思維才行啊,局限了。而且有時候就隻是一個很小的跳躍而已。
/AC
#include <cstdio>
#include <cstdlib>
struct node
{
long index;
node* next;
};
node* peo[1002];
long n;
const long oo = 0x7fff0000;
long s[1002][1002];
long f[1002];
bool used[1002];
int bigger(const void* a,const void* b)
{
long aa = *(long*)a;
long bb = *(long*)b;
if (aa>bb) return -1;
if (aa<bb) return 1;
return 0;
}
void dfs(long l)
{
if (f[l]>-oo) return;
node* ths = peo[l];
while (ths)
{
if (!used[ths->index])
{
used[ths->index] = true;
dfs(ths->index);
s[l][++s[l][0]] = f[ths->index];
used[ths->index] = false;
}
ths = ths->next;
}
if (s[l][0]==0)
{
f[l] = 0;
return;
}
qsort(s[l]+1,s[l][0],sizeof(s[1][0]),&bigger);
for (long i=1;i<s[l][0]+1;i++)
{
f[l] >?= s[l][i]+i;
}
}
void insert(long a,long b)
{
node* tmp = new node;
tmp->index = b;
tmp->next = peo[a];
peo[a] = tmp;
}
long fangan[1002];
int main()
{
freopen("news.in","r",stdin);
freopen("news.out","w",stdout);
scanf("%ld",&n);
for (long i=2;i<n+1;i++)
{
long a;
scanf("%ld",&a);
insert(a,i);
insert(i,a);
}
long ans = oo;
for (long i=1;i<n+1;i++)
{
for (long j=1;j<n+1;j++)
{
f[j] = -oo;
s[j][0] = 0;
}
used[i] = true;
dfs(i);
used[i] = false;
if (ans>f[i])
{
ans = f[i];
fangan[0] = 1;
fangan[1] = i;
}
else if (ans==f[i])
{
fangan[++fangan[0]] = i;
}
}
printf("%ld\n",ans+1);
for (long i=1;i<fangan[0]+1;i++)
printf("%ld ",fangan[i]);
}
覃禹舜,節約空間,選擇排序
program news;
type pnode=^node;
node=record
data:longint;
next:pnode;
end;
var
mark:array[0..1001] of boolean;
a,f,time:array[0..1001] of longint;
p:array[0..1001] of pnode;
max,len1,len2,t1,ans,n:longint;
procedure init;
begin
assign(input,'news.in');reset(input);
assign(output,'news.out');rewrite(output);
end;
procedure insert(x,y:longint);
var
point:pnode;
begin
new(point);
point^.data:=y;
point^.next:=p[x];
p[x]:=point;
end;
procedure readdata;
var
i,x:longint;
begin
fillchar(p,sizeof(p),0);
read(n);
for i:=2 to n do
begin
read(x);
insert(x,i); insert(i,x);
end;
end;
function work(x,last:longint):longint;
var
y:pnode;
flag:boolean;
begin
y:=p[x]; flag:=false;
while y<>nil do
begin
if y^.data<>last then
begin
flag:=true;
work(y^.data,x);
end;
y:=y^.next;
end;
if not flag then begin f[x]:=0; exit; end;
y:=p[x];
a[0]:=0;
while y<>nil do
begin
if y^.data<>last then begin inc(a[0]); a[a[0]]:=f[y^.data] end;
y:=y^.next;
end;
for len1:=2 to a[0] do
for len2:=1 to len1-1 do
if a[len2]<a[len1] then begin t1:=a[len2]; a[len2]:=a[len1]; a[len1]:=t1; end;
for len1:=1 to a[0] do inc(a[len1],len1);
max:=0;
for len1:=1 to a[0] do
if a[len1]>max then max:=a[len1];
f[x]:=max;
end;
procedure main;
var
i:longint;
begin
for i:=1 to n do
begin
work(i,0);
time[i]:=f[i];
end;
ans:=maxlongint;
for i:=1 to n do if time[i]<ans then ans:=time[i];
writeln(ans+1);
for i:=1 to n do
if time[i]=ans then write(i,' ');
end;
procedure terminate;
begin
close(input);close(output);
halt;
end;
begin
init;
readdata;
main;
terminate;
end.