Diary 10.4.2014

Ask:你昨天的題解呢? Ans:太水了就懶得寫了233

嗯剛剛發生了什麼?好像有什麼奇怪的東西被劃掉了。。

反正跟我沒關係23333

嗯。。今天貪心專場。。

1. 引爆炸彈(bomb.pas/c/cpp)
【問題描述】
有n個炸彈,有些炸彈牽了一根單向引線(也就是說引線只有在這一端能被炸彈點燃),只要引爆了這個炸彈,用引線連接的下一個炸彈也會爆炸。每個炸彈還有個得分,當這個炸彈被引爆後就能得到相應得分。現在要你引爆k個炸彈,使得得分最大。
【輸入】
第一行兩個整數n、k。
接下來的n行,每行兩個整數a[i]、b[i]。a[i]表示這個炸彈用引線連接的下一個炸彈,如果a[i]爲0,則表示這個炸彈沒有連接引線。b[i]表示這個炸彈的得分。
【輸出】
最多可分成的隊數。


本來是沒思路的,,然後一不小心看了Clarkok的博客。。

先把邊反向,搞一個虛擬根0,然後DFS

如果向下有分叉,就只連接最大的那個,剩下叉掉

然後找前k大。。

const 	shuru='bomb.in';
	    shuchu='bomb.out';
		rp=10086;
		maxn=200000+1;
		orz='Orz ZBT get full mark';
		OTZ='Orz Daily-AK LZW';
		OTL='Orz xudyh';
var num,a,headlist,t,next:array[0..maxn] of int64;
	sign,hash:Array[0..maxn] of boolean;
	b:Array[0..maxn] of int64;
	ans,change,p,x,j,k,n:int64;
	i:longint;
	sad:boolean;
procedure init;
begin	
	fillchar(hash,sizeof(hash),false);
	assign(input,shuru);
	assign(output,shuchu);
	reset(input);
	rewrite(output);
	readln(n,k);
	for i:=0 to n do headlist[i]:=-1;
	for i:=1 to n do
	begin
		readln(x,a[i]);
		inc(p);
		next[p]:=headlist[x];
		headlist[x]:=p;
		t[p]:=i;
	end;
	a[0]:=0;
	close(input);
end;
Procedure dfs(u:longint);
var i,step,step1:longint;
begin
	hash[u]:=true;
	if headlist[u]=-1 then begin
							num[u]:=a[u];
							exit;
						   end;
	if next[headlist[u]]=-1 then begin
									dfs(t[headlist[u]]);
									num[u]:=num[t[headlist[u]]]+A[u];
								 end;
	i:=headlist[u];
	step:=0;
	while i<>-1 do
	begin
		dfs(t[i]);
		if num[t[i]]>Step then begin
								step:=num[t[i]];
								step1:=t[i];
							   end;
		i:=next[i];
	end;
	num[u]:=step+a[u];
	i:=headlist[u];
	while i<>-1 do
	begin
		if t[i]<>step1 then sign[t[i]]:=true;
		i:=next[i];
	end;
end;
procedure qsort(left,right:longint);
var i,j,mid:longint;
begin
	i:=left; j:=right; mid:=b[(i+j) div 2];
	repeat
		while b[i]>mid do inc(i);
		while b[j]<mid do dec(j);
		if i<=j then begin
						change:=b[i];
						b[i]:=b[j];
						b[j]:=change;
						inc(i); dec(j);
					 end;
	until i>j;
	if j>left  then qsort(left,j);
	if i<right then qsort(i,right);
end;
Procedure main;
begin
	init;
	dfs(0);
	sign[0]:=true;
	sad:=true;
	for i:=0 to n do sad:=sad and hash[i];
	if sad=false then begin
						writeln('喪心病狂');
						halt;
					  end;
	p:=0;
	for i:=0 to n do
		if sign[i] then begin
							inc(p);
							b[p]:=num[i];
						end;
	qsort(1,p);
	for i:=1 to k do
		ans:=ans+b[i];
	writeln(ans);
	close(output);
end;
begin
	main;
end.


2. 取石子(stone.pas/c/cpp)
【問題描述】 有n個石子圍成一圈,每個石子都有一個權值a[i]。給你一次且僅一次取石子的機會,取石子的塊數不限,取完後統計得分。現在要使取出的石子得分最大。
每個石子的得分計算公式是a[i]*d,d表示這個石子到兩邊被取了的石子的距離和。如{1,2,7,9,8,6,4,5,3,10}這些權值的石子圍成一圈,不同取法有不同得分:
【輸入】 第一行一個整數n。接下來n行,每行一個整數a[i]。

嗯想到是貪心專場,所以往貪心上想。。

想了半天,沒想出來,覺得是個神貪心。。

後來發現真的是‘神’貪心啊

我們發現取3 個石子和3 個以上石子一定不會得到最優解。那麼只可能是取兩個或者一個石子,設max1 表示所有石子中權值最大的一個,max2 表示所有石子中權值第二大的一個,那麼答案一定是Max{(max1+max2)*(n-2),max1*(n-1)}

然後找最大和第二大的程序寫錯了就只有40分了233 我是傻叉我驕傲!

const shuru='stone.in';
	  shuchu='stone.out';
	  rp=10086;
	  orz='Daily-AK Lzw';
	  OTZ='Daily-AK yyl';
	  OTL='Daily-AK zbt';
	  SCH='Daily-00 wjz';
var t,k,n,x:int64;
	a:Array[0..100000] of int64;
	i,j:longint;
Function max(a,b:int64):int64;
begin
	if a>b then exit(A);
	exit(b);
end;
procedure init;
begin
	assign(input,shuru);
	assign(output,shuchu);
	reset(input);
	rewrite(output);
	readln(n);
	for i:=1 to n do
		readln(a[i]);
end;
procedure qsort(left,right:longint);
var i,j,mid:longint;
begin
	i:=left; j:=right; mid:=a[(i+j) div 2];
	repeat	
		while a[i]<mid do inc(i);
		while a[j]>mid do dec(j);
		if i<=j then begin
						t:=a[i];
						a[i]:=a[j];
						a[j]:=t;
						inc(I); dec(j);
					 end;
	until i>j;
	if j>left  then qsort(left,j);
	if i<right then qsort(i,right);
end;
procedure main;
begin
	init;
	qsort(1,n);
	writeln(max(a[n]*(n-1),(a[n]+a[n-1])*(n-2)));
	close(output);
end;
begin
	main;
end.

T3


嗯。。

我今天寫題解的主要原因就是因爲這一題

因爲這代表了一類DP

具體描述起來就是

有多種物品需要被製造,每種物品有製造的時間,求利益最大什麼什麼的這樣

【問題描述】
一個軟件開發公司同時要開發兩個軟件,並且要同時交付給用戶,現在公司爲了儘快完成這一任務,將每個軟件劃分成m個模塊,由公司裏的技術人員分工完成,每個技術人員完成同一軟件的不同
YZOI-NOIP2014 第二輪模擬(二)day1 ~ 2 ~
模塊的所用的天數是相同的,並且是已知的,但完成不同軟件的一個模塊的時間是不同的,每個技術人員在同一時刻只能做一個模塊,一個模塊只能由一個人獨立完成而不能由多人協同完成。一個技術人員在整個開發期內完成一個模塊以後可以接着做任一軟件的任一模塊。寫一個程序,求出公司最早能在什麼時候交付軟件。
【輸入】輸入文件第一行包含兩個由空格隔開的整數n和m,其中1≤n≤100,1≤m≤100。接下來的n行每行包含兩個用空格隔開的整數d1和d2,d1表示該技術人員完成第一個軟件中的一個模塊所需的天數,d2表示該技術人員完成第二個軟件中的一個模塊所需的天數,其中l≤d1,d2≤100。
【輸出】輸出文件僅有一行包含一個整數d,表示公司最早能於d天后交付軟件。

嗯就是像這樣子的題目。。

這樣子通常是怎麼樣子呢。。通常是把時間,以及做的件數放在狀態裏

比如上面那個例子就是f[i,j]就是前i個程序員在k(已給出)時間內做了i個n任務後最多能做多少m任務

這道題也是,就是f[i,a,b,c]表示前i-1個已經放好,現在有a個a,b個b,c個c,接下來最少要裝多少次箱?

那麼通過 f[i][A][B][C]可以正向推出3 個決策
把A裝箱:f[i+A][A’][B+B’][C+C’],其中A’,B’,C’表示流水線上第i 到第i+A-1
個產品中分別有多少個A 類,B 類,C 類產品。
把 B 裝箱:f[i+B][A+A’][B’][C+C’],其中A’,B’,C’表示流水線上第i 到第i+B-1
個產品中分別有多少個A 類,B 類,C 類產品。
把 C 裝箱:f[i+C][A+A’][B+B’][C’],其中A’,B’,C’表示流水線上第i 到第i+C-1
個產品中分別有多少個A 類,B 類,C 類產品。
f[i][A][B][C]=min{f[i+A][A’][B+B’][C+C’],f[i+B][A+A’][B’][C+C’],f[i+C][A+A’][B+B’][C’]}+1



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章