09-Day1 題解

被催着做了Test 09-Day1..

嗯那我就寫一下題解了。。

1. 詞編碼(word.pas/c/cpp)
【問題描述】
一個發送機可以通過一條隧道發送一些以二進制代碼組成的單詞。在其盡頭的接受機可以使用特殊技術恢復到最初的單詞。每個單詞最初都由0和1組成。所有的單詞最初長度都爲n(4<=n<=1000)。當穿過隧道之後單詞可能發生以下幾種情況之一:
(1)任意(一個)0被1取代;
(2)任意(一個)符號被刪除;
(3)一個符號(0或1)被插入到任何位置;
(4)不改變。
我們知道最初的單詞都具有以下性質:有1的位置號的總和是n+1的倍數,或者是0。
【輸入】
n和轉換後的單詞,每個單詞佔一行。單詞數不大於2001,不會有其他任何東西,除了空格和空行。
【輸出】你的程序應該打印輸出原始序列的詞,注意換行。若有多解,操作4有限,不行則按操作1、2、3優先。同一操作,按操作位置最先的優先(從左到右數起1、2、3…n)。對於操作2,先在被刪數列添0,不行再添1。如果沒有答案則輸出-1。


碼農題。。

剛開始沒看到原來長度是n被坑了一把。。

const shuru='word.in';
	  shuchu='word.out';
var	s:array[0..1001] of char;
	count,tot,len,i,j,k,n:longint;
	a,d:array[0..1001] of longint;
	sign:boolean;
procedure setIO;
begin
	assign(input,shuru);reset(input);
	assign(output,shuchu);rewrite(output);
	readln(n);
end;
procedure closeIO;
begin
	close(input); close(output);
end;
procedure main;
begin
	setIO;
	while not(eof) do
	begin
		tot:=0; len:=0; count:=0;
		a[0]:=0; sign:=false;
		while not(eoln) do
		begin
			inc(len);
			read(s[len]);
			if s[len]='1' then begin
								inc(tot,len);
								inc(count);
								d[count]:=len;
								a[len]:=a[len-1]+1
							 end
						  else a[len]:=a[len-1];
		end;
		readln;
		if len=n then begin
		if tot mod (len+1)=0 then begin
									for k:=1 to len do write(s[k]);
									writeln;
									continue;
								  end;
		for i:=1 to count do
			if (tot-d[i]) mod (len+1)=0 then begin
												for k:=1 to d[i]-1 do write(s[k]);
												write(0);
												for k:=d[i]+1 to len do write(s[k]);
												writeln;
												sign:=true;
												break;
											 end;
		if sign then continue;
		writeln(-1);
		continue;
					   end;
		if len=n-1 then begin
		for i:=1 to len do
			if (tot+a[len]-a[i-1]) mod (len+2)=0 then begin
														for k:=1 to i-1 do write(s[k]);
														write(0);
														for k:=i to len do write(s[k]);
														writeln;
														sign:=true;
														break;
													end;
		if sign then continue;
		if tot mod (len+2)=0 then begin
									for k:=1 to len do write(s[k]);
									writeln(0);
									continue;
								  end;
		for i:=1 to len do
			if (tot+a[len]-a[i-1]+i) mod (len+2)=0 then begin
														for k:=1 to i-1 do write(s[k]);
														write(1);
														for k:=i to len do write(s[k]);
														writeln;
														sign:=true;
														break;
													end;
		if sign then continue;
		if (tot+len+1) mod (len+2)=0 then begin
											for k:=1 to len do write(s[k]);
											writeln(1);
											continue;
										  end;
		writeln(-1);
		continue;
		end;
		for i:=1 to len do
			case s[i] of
				'0':if (tot-(a[len]-a[i])) mod len=0 then begin
															for k:=1 to i-1 do write(s[k]);
															for k:=i+1 to len do write(s[k]);
															writeln;
															sign:=true;
															break;
														  end;
				'1':if (tot-i-(a[len]-a[i])) mod len=0 then begin
															for k:=1 to i-1 do write(s[k]);
															for k:=i+1 to len do write(s[k]);
															writeln;
															sign:=true;
															break;
														  end;
					end;
		if not(sign) then writeln(-1);
	end;
end;
begin
	main;
end.
		
T2

2. 笨笨粉刷匠(draw.pas/c/cpp)
【問題描述】
笨笨太好玩了,農田荒蕪了,彩獎用光了,笨笨只好到處找工作,笨笨找到了一份粉刷匠的工作。
笨笨有n 條木板需要被粉刷。每條木板被分成m 個格子,每個格子要被刷成紅色或藍色。笨笨每次粉
刷,只能選擇一條木板上一段連續的格子,然後塗上一種顏色,已知每個格子最多隻能被粉刷一次。
如果笨笨只能粉刷t 次,他最多能正確粉刷多少格子。
一個格子如果未被粉刷或被粉刷成錯誤顏色,就算粉刷錯誤。
【輸入】
第一行三個數n,m,t;
接下來n 行,每行一個長度爲m 的字符“0”表示紅色,"1"表示藍色。
【輸出】
一個整數,最多能正確粉刷的格子數。

看到題的時候在猜。。猜是DP還是貪心。。

不過覺得貪心不大可能,就想是DP

然後想到了某一行塗k次的DP轉移方程。。

設f[i,j]表示前i個塗j次最多能塗對多少個。

f[i,j]:=max(f[i-1,j],f[k,j]+best[k+1,i]){其中best[k+1,j]表示從k+1到j 0和1個數中較大的那個。。

然後發現不會合並。。。

想了很久。。

後來很棄療地看了lzw大神的博客。。

發現是揹包233333.

以後這種資源分配的需要合併用揹包。。

也算是學到了一點東西吧。。

Code:

const shuru='draw.in';
	  shuchu='draw.out';
	  maxn=51;
	  maxt=2501;
var f:array[0..maxn,0..maxt] of longint;
	a:array[0..maxn,0..maxn] of char;
	p,q:array[0..maxn,0..maxn] of longint;
	v:array[0..maxn,0..maxn] of longint;
	ans:array[0..maxt] of longint;
	pp,step,l,i,j,k,n,m,t:longint;
function min(a,b:longint):longint;
begin
	if a<b then exit(a);
	exit(b);
end;
procedure init;
begin
	assign(input,shuru);reset(input);
	assign(output,shuchu);rewrite(output);
	readln(n,m,t);
	if n*m=t then begin
					writeln(t);
					close(input);close(output);
					halt;
				  end;
	for i:=1 to n do
	begin
		for j:=1 to m do
			read(a[i,j]);
		readln;
	end;
end;
function max(a,b:longint):longint;
begin
	if a>b then exit(a);
	exit(b);
end;
procedure main;
begin
	init;
	step:=min(m,t);
	for k:=1 to n do
	begin
		fillchar(p,sizeof(p),0);
		fillchar(q,sizeof(q),0);
		for i:=1 to m do
			for j:=i to m do
				if a[k,j]='1' then begin
									p[i,j]:=p[i,j-1]+1;
									q[i,j]:=q[i,j-1];
								 end
							else begin
									p[i,j]:=p[i,j-1];
									q[i,j]:=q[i,j-1]+1;
								 end;
		for i:=1 to m do
			for l:=1 to step do
			begin
				f[i,l]:=f[i-1,l];
				for j:=0 to i-1 do
					f[i,l]:=max(f[i,l],f[j,l-1]+max(p[j+1,i],q[j+1,i]));
			end;
		for i:=0 to step do
			v[k,i]:=f[m,i];
	end;
	for k:=1 to n do
		for j:=t downto 0 do
		begin
			pp:=min(j,step);
			for i:=0 to pp do
				ans[j]:=max(ans[j],ans[j-i]+v[k,i]);
		end;
	writeln(ans[t]);
	close(output); close(input);
end;
begin
	main;
end.
3. 笨笨的電話網絡(phone.pas/c/cpp)
【問題描述】
多年以後,笨笨長大了,成爲了電話線佈置師。由於地震使得某市的電話線全部損壞,笨笨是負責將電話線接到該市的負責人。該市周圍分佈着N(1≤N≤1000)根按1..N順次編號的廢棄的電話線杆,任意兩根電話線杆間都沒有電話線相連。一共P(1≤P≤10000)對電話線杆間可以拉電話線,其餘的由於地震使得無法被連接。
第i對電話線杆的兩個端點分別爲Ai,Bi,它們間的距離爲Li(1≤Li≤1000000)。數據保證每對(Ai,Bi)最多隻出現1次。編號爲1的電話線杆已經接入了全國的電話網絡,整個市的電話線全都連到了編號爲N的電話線杆上。也就是說,笨笨的任務僅僅是找一條將1號和N號電話線杆連起來的路徑,其餘電話線杆並不一定要連入電話網絡。
電信公司決定支援災區免費爲該市連接K(0≤K≤N)對由笨笨指定的電話線杆。對於此外的那些電話線,需要爲它們付費,總費用等於其中最長的電話線的長度(每根電話線僅連接一對電話線杆)。如果需要連接的電話線杆不超過K對,那麼總支出爲0。
笨笨需要計算一下,將電話線引到震中市最少需要在電話線上花多少錢?
【輸入】
輸入文件的第一行包含三個用空格隔開的整數:N,P和K。
第二行到第P+1行:每行分別都爲三個用空格隔開的整數:Ai,Bi和Li。
【輸出】輸出文件中僅包含一個整數,表示在這項工程上的最小支出。如果任務不可能完成,則輸出-1。

這題是某一天早上模模糊糊想出來的。。

很明顯就是找這樣一條路,使它的第k+1大的邊最小

這種什麼xxx的最小肯定用二分答案,轉化成判定問題

二分答案後,對所有的邊,如果它大於他,就是1,否則就是0.

然後做最短路,如果小於等於k,就可以的。。

最開始數組開小隻拿了30分真是開心。。

const shuru='phone.in';
	  shuchu='phone.out';
	  maxn=1001;
	  maxm=20002;
	  INF=1 shl 26;
	  long=40*maxn;
var	d,headlist:array[0..maxn] of longint;
	weight,w,t,next:Array[0..maxm] of longint;
	queue:array[0..long] of longint;
	inq:Array[0..maxn] of boolean;
	a:Array[0..maxm] of longint;
	l,r,mid,ans,data,front,finish,p,i,j,k,n,m,x,y,z,num:longint;
procedure init;
begin
	assign(input,shuru);reset(input);
	assign(output,shuchu);rewrite(output);
	readln(n,m,k);
	for i:=1 to n do headlist[i]:=-1;
	for i:=1 to m do
	begin
		readln(x,y,z);
		a[i]:=z;
		inc(num);
		next[num]:=headlist[x];
		headlist[x]:=num;
		t[num]:=y;
		weight[num]:=z;
		inc(Num);
		next[num]:=headlist[y];
		headlist[y]:=num;
		t[num]:=x;
		weight[num]:=z;
	end;
	close(input);
end;
procedure qsort(left,right:longint);
var i,j,mid:longint;
begin
	i:=left; j:=right; mid:=a[(i+j) shr 1];
	repeat
		while a[i]<mid do inc(i);
		while a[j]>mid do dec(j);
		if i<=j then begin
						p:=a[i];
						a[i]:=a[j];
						a[j]:=p;
						inc(i);
						dec(j);
					 end;
	until i>j;
	if j>left  then qsort(left,j);
	if i<right then qsort(i,right);
end;
function spfa(sign:longint):longint;
var i:longint;
begin
	w:=weight;
	for i:=1 to num do if w[i]>sign then w[i]:=1 else w[i]:=0;
	fillchar(inq,sizeof(inq),false);
	for i:=1 to n do d[i]:=INF;
	d[1]:=0;
	queue[1]:=1; inq[1]:=true;
	front:=0; finish:=1;
	while front<>finish do
	begin
		inc(front);
		if front>long then front:=front-long;
		x:=queue[front];
		i:=headlist[x];
		inq[x]:=false;
		while i<>-1 do
		begin
			if d[t[i]]>d[x]+w[i] then begin
										d[t[i]]:=d[x]+w[i];
										if not(inq[t[i]]) then begin
																	inc(finish);
																	if finish>long then finish:=finish-long;
																	queue[finish]:=t[i];
																	inq[t[i]]:=true;
															   end;
									  end;
			i:=next[i];
		end;
	end;
	exit(d[n]);
end;
function min(a,b:longint):longint;
begin
	if a<b then exit(a);
	exit(b);
end;
procedure main;
begin
	init;
	data:=spfa(-1);
	if data<=k then begin
						writeln(0);
						close(output);
						halt;
					end;
	if d[n]=INF then begin
						writeln(-1);
						close(output);
						halt;
					 end;
	qsort(1,m);
	l:=1; r:=m; ans:=INF;
	repeat
		mid:=(l+r) shr 1;
		data:=spfa(a[mid]);
		if data<=k then begin
							ans:=min(ans,a[mid]);
							r:=mid-1;
						end
				   else l:=mid+1;
	until l>r;
	writeln(ans);
	close(output);
end;
begin
	main;
end.



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