申請SAE

如果您發現本博客的外觀很難看,那是因為部分外觀文件被中國.國家.防火.牆屏.蔽所致!
請翻~牆!

我的Wordpress博客的地址: http://zhuyf.tk/
顯示具有 動態規劃 標籤的文章。 顯示所有文章
顯示具有 動態規劃 標籤的文章。 顯示所有文章

2012年2月27日 星期一

動態規劃練習題 相似基因 gene 題解

問題描述
大家都知道,基因可以看作一個鹼基對序列。它包含了 4 種核苷酸,簡記作 A,C,G,T 。生物學家正致力於尋找人類基因的功能,以利用於診斷疾病和發明藥物。
在一個人類基因工作組的任務中,生物學家研究的是:兩個基因的相似程度。因為這個研究對疾病的治療有著非同尋常的作用。兩個基因的相似度的計算方法如下:
對於兩個已知基因,例如 AGTGATG 和 GTTAG ,將它們的鹼基互相對應。當然,中間可以加入一些空鹼基 - ,例如:

A G T G A T - G
- G T - - T A G

這樣 , 兩個基因之間的相似度就可以用鹼基之間相似度的總和來描述,鹼基之間的相似度如下表所示:

那麼相似度就是: (-3)+5+5+(-2)+(-3)+5+(-3)+5=9 。因為兩個基因的對應方法不唯一,例如又有:
A G T G A T G
- G T T A - G

相似度為: (-3)+5+5+(-2)+5+(-1)+5=14 。規定兩個基因的相似度為所有對應方法中,相似度最大的那個。

2012年2月20日 星期一

[動態規劃]Ural 1031 rail 火車票 解題報告

【題目描述】
現在有一條“葉卡特琳堡-斯維爾德洛夫斯克”鐵路線。它有若干個火車站。這個鐵路線可以用一條線段來表示,而火車站就是線段上的點。鐵路起始於葉卡特琳堡(Eakterinburg),終止於斯維爾德洛夫斯克(Sverlovsk),且各站從葉卡特琳堡(它的編號是1)至斯維爾德洛夫斯克(終點)編號。



兩個站之間的票價僅跟兩站間的距離有關係。票價規定如下表。

兩站間距離 - X
票價

0<X<=L1

C1

L1<X<=L2

C2

L2<X<=L3

C3

當且僅當兩站間距離不大於L3時才能購買這兩站之間的直達車票。所以有時須要購買若干張票來完成整個旅行。


例如,在上圖,整條鐵路有七個站。從第2站不能直達第6站(因為距離大於L3),但有另外幾種方法購票。其中一種是買兩張票:一張是從第2站至第3 站(票價為C2),另一張是從第3站至第6站(票價為C3),注意,雖然從第2站至第6站的距離為2×L2,但不可以買兩張價值C2的票,因為一張票只可以用一次且起點和終點必須在車站上。

你的任務時計算給出的兩站之間的最小花費。

[動態規劃]OI練習題 週年紀念聚會 aniv 解題報告

週年紀念聚會

Background
校長正在籌備學校的80週年紀念聚會。由於學校的職員有不同的職務級別,可以構成一棵以校長為根的人事關係樹。每個職員都有一個唯一的整數編號(範圍在1到N之間),並且對應一個參加聚會所獲得的歡樂度。為了使每個參加聚會者都感到歡樂,校長想設法使每個職員和他(她)的直接上司不會同時參加聚會。
Problem
你的任務是設計一份參加聚會者的名單,使總的歡樂度最高。
Input
輸入的第一行是一個整數N,1<= N <= 6000
以下的N行是對應的N個職員的歡樂度(歡樂度是一個從-128到127之間的整數)
接著是學校的人事關係樹,樹的每一行格式如下:
<L> <K>
表示第K個職員是第L個職員的直接上司。
輸入以0 0表示結束
輸出:參加聚會者獲得的最大總歡樂度

[動態規劃]OI練習題 最後的利益 9cwy 解題報告

【問題描述】
最近9C馬上就要和WY交收WOW的運營權了,9C為了最後的利益決定讓GM控制玩家上線時間。因為9C的小霸王伺服器總是容易爆滿,所以某伺服器中只剩一個玩家的位子,GM為了讓玩家在線時間總和最長。他將選擇一些上線時間不重複的玩家讓他們上線。我們假設某玩家下線以後,另一個玩家可以立即登入。但是GM又笨又懶,他希望你能幫他幫他寫一個程序來完成這個任務。
【輸入文件】
輸入文件第一行是一個正整數n,n<=10000,為玩家數量
一下n行每行含有兩個數t1、t2表示某玩家上線時段
【輸出文件】
輸出最長遊戲總時間

[動態規劃]POI 1998 ple 潛水員問題 解題報告

【問題描述】
     一個潛水員在潛水時使用一種特殊的裝置:一個有兩個容器的氣筒。一個容器中裝的是氧氣,另一個容器中裝氮氣。潛水員需要攜帶的氧氣和氮氣量依賴於潛水的時間和深度。潛水員有一系列的氣筒,用來在不同的情況下攜帶。每個氣筒可以用這樣幾個量來描述:氣筒的質量,氣筒中所能容納的氧氣量,以及可以容納的氮氣量。為了能完成最近的一個任務,潛水員需要一定量的氧氣和氮氣。潛水員有一系列準備好的氣筒。他希望能攜帶總質量儘可能小的氣筒下水。現在請你幫他計算一下至少要攜帶多少質量的氣筒下水才能完成這個任務。

示例說明
潛水員有以下 5 個氣筒。每個氣筒用三個整數來描述:氣筒所能容納的氧氣的量,氮氣的量和氣筒的質量:

3 36 120
10 25 129
5 50 250
1 45 130
4 20 119
如果這次任務中潛水員需要攜帶 5 升 氧氣, 60 升 氮氣。那麼他至少要攜帶總質量為 249 的氣筒下水(樣例中的第一個和第二個氣筒或者第四個和第五個氣筒)。

2012年2月10日 星期五

[記憶化搜索]USACO Jan09 Silver Laserphones 激光電話



**********************************************************************

Problem 8: Laserphones [Rob Kolstad, 2008]

The cows have a new laser-based system so they can have casual
conversations while out in the pasture which is modeled as a W x H
grid of points (1 <= W <= 100; 1 <= H <= 100).

The system requires a sort of line-of-sight connectivity in order
to sustain communication. The pasture, of course, has rocks and
trees that disrupt the communication but the cows have purchased
diagonal mirrors ('/' and '\' below) that deflect the laser beam
through a 90 degree turn. Below is a map that illustrates the
problem.

2012年2月6日 星期一

USACO Oct07 Silver 障礙訓練場 obstacle 解題報告

Title: 障礙訓練場
Input: obstacle.in
Output: obstacle.out
Time Limit: 1000 ms
Memory Limit: 128 MB
Level: ★☆
譯 By CmYkRgB123
考慮一個 N x N (1 <= N <= 100)的有1個個方格組成的正方形牧場。有些方格是奶牛們不能踏上的,它們被標記爲了'x'。例如下圖:
        . . B x .
        . x x A .
        . . . x .
        . x . . .
        . . x . .
貝茜發現自己恰好在點A出,她想去B處的鹽塊添鹽。緩慢而且笨拙的動物,比如奶牛,十分討厭轉彎。儘管如此,當然在必要的時候她們還是會轉彎的。對於一個給定的牧場,請你計算從A到B最少的轉彎次數。開始的時候,貝茜可以使面對任意一個方向。貝茜知道她一定可以到達。

2012年2月3日 星期五

【動態規劃】IOI2000 回文詞

Title: 回文詞
Input: palin.in
Output: palin.out
Time Limit: 1000 ms
Memory Limit: 128 MB
Level: ★☆
【问题描述】
    迴文詞是一種對稱的字元串——也就是說,一個迴文詞,從左到右讀和從右到 左讀得到的結果是一樣的。任意給定一個字元串,通過插入若干字元,都可以變成一個迴文 詞。你的任務是寫一個程序,求出將給定字元串變成迴文詞所需插入的最少字元數。 比如字元串“Ab3bd”,在插入兩個字元後可以變成一個迴文詞(“dAb3bAd” “Adb3bdA”)。然而,插入兩個以下的字元無法使它變成一個迴文詞。

2012年2月2日 星期四

USACO Feb07 奶牛詞典 Cow Lexicon

Title: 奶牛詞典
Input: lexicon.in
Output: lexicon.out
Time Limit: 1000 ms
Memory Limit: 128 MB
Level: ★★
譯: zqzas

題目描述:

沒有幾個人知道,奶牛有她們自己的字典,裡面的有W (1 ≤ W ≤ 600)個詞,每個詞的長度不超過25,且由小寫字母組成.她們在交流時,由於各種原因,用詞總是不那麼準確.比如,貝茜聽到有人對她 說"browndcodw",確切的意思是"browncow",多出了兩個"d",這兩個"d"大概是身邊的噪音.

奶牛們發覺辨認那些奇怪的資訊很費勁,所以她們就想讓你幫忙辨認一條收到的消息,即一個只包含小寫字母且長度為L (2 ≤ L ≤ 300)的字元串.有些時候,這個字元串裡會有多餘的字母,你的任務就是找出最少去掉幾個字母就可以使這個字元串變成準確的"牛語"(即奶牛字典中某些詞 的一個排列).



2012年1月29日 星期日

[動態規劃]OI練習題:取數字遊戲 number

Title: 取數字遊戲【試題連結
Input: number.in
Output: number.out
Time Limit: 1000 ms
Memory Limit: 128 MB
Level: ★☆
【問題描述】
給定 M*N 的矩陣,其中的每個元素都是 -10 到 10 之間的整數。你的任務是從左上角( 1 , 1 )走到右下角( M , N ),每一步只能向右或向下,並且不能走出矩陣的範圍。你所經過的方格裏面的數字都必須被選取,請找出一條最合適的道路,使得在路上被選取的數字之和是儘可能小的正整數。

2012年1月28日 星期六

[RMQ問題]OI練習題:綿延的山峰 climb 解題報告

Title: 延綿的山峰 傳送門
Input: climb.in
Output: climb.out
Time Limit: 1000 ms
Memory Limit: 128 MB
Level: ★★

問題描述
 
有一座延綿不斷、跌宕起伏的山,最低處海拔為0,最高處海拔不超過8848米,從這座山的一端走到另一端的過程中,每走1米海拔就升高或降低1米。有Q個登山隊計劃在這座山的不同區段登山,當他們攀到各自區段的最高峯時,就會插上隊旗。請你寫一個程序找出他們插旗的高度。

[字典樹]OI練習題:詞鏈 link 解題報告

Title: 詞鏈【傳送門
Input: link.in
Output: link.out
Time Limit: 1000 ms
Memory Limit: 128 MB
Level: ★☆
【問題描述】
給定一個僅包含小寫字母的英文單詞表,其中每個單詞最多包含 50 個字母。
如果一張由一個詞或多個片語成的表中,每個單詞(除了最後一個)都是排在它後面的單詞的前綴,則稱此表為一個詞鏈。例如下面的單片語成了一個詞鏈:
i
int
integer
而下面的單詞不組成詞鏈:
integer
intern
請在給定的單詞表中取出一些詞,組成最長的詞鏈。最長的詞鏈就是包含單詞數最多的詞鏈。
資料保證給定的單詞表中,單詞互不相同,並且單詞按字典順序排列。

2012年1月25日 星期三

POI1997 階梯教室設備利用 rez 解題報告

階梯教室設備利用
【問題描述】
我們現有許多演講要在階梯教室中舉行。每一個演講都可以用唯一的起始和終止時間來確定,如果兩個演講時間有部分或全部重複,那麼它們是無法同時在階級教室中舉行的。現在我們想要盡最大可能的利用這個教室,也就是說,我們需要在這些演講中選擇一些不重複的演講來舉行使得他們用的總時間儘可能的長。我們假設在某一演講結束的瞬間我們就可以立即開始另一個演講。
任務:
請寫一個程序:
• 在輸入文件中讀入所有演講的起始和終止時間;
• 計算最大的可能演講總時間;
• 把結果寫到輸出文件中。
【輸入文件】
在輸入文件的第一行包括一個正整數 n , n <= 10000 ,為所有的演講的數目。
以下的 n 行每行含有兩個由空格隔開整數 p 和 k , 0 <= p < k <= 30000 。這樣的一對整數表示一個演講由時間 p 開始到時間 k 結束。
【輸出文件】
輸出文件只有唯一的一個整數,為最長的演講總時間。

2012年1月18日 星期三

[動態規劃]OI練習題:打鼴鼠 mouse 解題報告


【問題背景】
鼴鼠是一種很喜歡挖洞的動物,但每過一定的時間,它還是喜歡把頭探出到地面上來透透氣的。
根據這個特點阿Q編寫了一個打鼴鼠的遊戲:在一個n*n的網格中,在某些時刻鼴鼠會在某一個網格探出頭來透透氣。你可以控制一個機器人來打鼴鼠,如果i時刻鼴鼠在某個網格中出現,而機器人也處於同一網格的話,那麼這個鼴鼠就會被機器人打死。而機器人每一時刻只能夠移動一格或停留在原地不動。機器人的移動是指從當前所處的網格移向相鄰的網格,即從座標為(i,j)的網格移向(i-1, j),(i+1, j),(i,j-1),(i,j+1)四個網格,機器人不能走出整個n*n的網格。遊戲開始時,你可以自由選定機器人的初始位置。
【任務描述】
現在你知道在一段時間內,鼴鼠出現的時間和地點,希望你編寫一個程序使機器人在這一段時間內打死儘可能多的鼴鼠。

2012年1月13日 星期五

[圖論]OI練習題:商人的宣傳 merchant 解題報告

題目連結:http://cogs.yeefanblog.tk/t/441


【問題描述】


Bruce是K國的商人,他在A州成立了自己的公司,這次他的公司生產出了一批性能很好的產品,準備宣傳活動開始後的第L天到達B州進行新品拍賣,期間Bruce打算將產品拿到各個州去做推銷宣傳,以增加其影響力。
K國有很多個州,每個州都與其他一些州相鄰,但是K國對商人作宣傳卻有一些很奇怪的規定:
(1)商人只能從某些州到達另外一些州,即連通路綫是單向的,而且有些州可能是到達不了的。
(2)商人不允許在同一個州連續宣傳兩天或以上,每天宣傳完必須離開該州。
(3)商人可以多次來到同一個州進行宣傳。
Bruce想:“我必須找出一條影響力最大的路綫才行,但首先必須知道到底有多少這種符合規定的宣傳路綫可供我選擇。”現在Bruce把任務交給了你,並且出於考慮以後的需要,你還要幫他算出給出的兩州之間的路綫的總數。
【輸入格式】
輸入格式(輸入文件名merchant.in)
輸入文件第1行包含3個整數n,m,L(1≤n,L≤100),分別表示K國的州數、連通路綫的數量,以及多少天后必須到達B州。
接下來有m行,每行一對整數五),(1≤x,y≤n),表示商人能從x州到達y州。
第m+2行爲一個整數q(1≤q≤100),表示Bruce有q個詢問。
下面q行每行兩個整數A,B(1≤A,B≤n),即A、B州的位置。

【輸出格式】
輸出格式(輸出文件名merchant.out)
輸出文件包含q行,每行一個整數t,爲所求的從A州到B州滿足上述規定的路綫總數。
輸入數據中的詢問將保證答案f在長整數範圍內,即i<2^31。

【輸入輸出樣例】
輸入(merchant.in)
4 5 6
1 2
2 3
3 4
4 1
2 4
2
1 4
4 2
輸出(merchant.out)
2
1

[分析]

這種題型我也不知道怎麽去描述,貌似是圖論中的DP~~我用了Floyd的框架寫的。Floyd算法其實就是動態規劃。因爲需要L天的宣傳,所以需要執行“Floyd 變形算法” L-1次。


我的程序的時間複雜度:O(L*n^3)

[我的代碼]

C++语言: Codee#25159
01 /*
02 *Prob:商人的宣傳(http://cogs.yeefanblog.tk/t/441)
03 *Author:Yee-fan Zhu(http://www.yeefanblog.tk/)
04 */
05 #include <iostream>
06 #include <cstdio>
07 #include <cstdlib>
08 using namespace std;
09
10 const int MAXN=101;
11 int Temp[MAXN][MAXN];
12 int Result[MAXN][MAXN];
13 int Start[MAXN][MAXN];
14
15 int N,M,L;
16
17 void init()
18 {
19     scanf("%d %d %d\n",&N,&M,&L);
20    
21     for (int i=1;i<=N;i++)
22         for (int j=1;j<=N;j++)
23             Temp[i][j]=0,
24             Result[i][j]=0,
25             Start[i][j]=0;
26    
27     for (int i=1;i<=M;i++)
28     {
29         int x,y;
30         scanf("%d %d\n",&x,&y);
31         Start[x][y]++;
32         Result[x][y]++;
33     }
34 }
35
36 void work()
37 {
38     for (int m=1;m<=L-1;m++)
39     {
40         for (int i=1;i<=N;i++)
41             for (int j=1;j<=N;j++)
42                 Temp[i][j]=Result[i][j],Result[i][j]=0;
43        
44         for (int i=1;i<=N;i++)
45             for (int j=1;j<=N;j++)
46                 for (int k=1;k<=N;k++)
47                     Result[i][j]+=Temp[i][k]*Start[k][j];
48     }
49    
50     int Q,x,y;
51     scanf("%d\n",&Q);
52     for(int i=1;i<=Q;i++)
53     {     
54         scanf("%d %d\n",&x,&y);
55         printf("%d\n",Result[x][y]);
56     }
57 }
58
59 int main()
60 {
61     freopen("merchant.in","r",stdin);
62     freopen("merchant.out","w",stdout);
63     init();
64     work();
65     return 0;
66 }

2011年12月14日 星期三

動態規劃練習題:填加號 解題報告

【問題描述】
有一個由數字 1 , 2 , … , 9 組成的數字串(長度不超過 200 ),問如何將 M(M<=20) 個加號 (“+”) 插入到這個數字串中,使所形成的算術表達式的值最小。請編一個程序解決這個問題。 注意: 加號不能加在數字串的最前面或最末尾,也不應有兩個或兩個以上的加號相鄰。 M 保證小於數字串的長度。 例如:數字串 79846 ,若需要加入兩個加號,則最佳方案為 79+8+46 ,算術表達式的值 133 。
【輸入格式】
數字串在輸入文件的第一行行首(數字串中間無空格且不折行),M的值在輸入文件的第二行行首。
【輸出格式】
輸出所求得的最小和的精確值。
【輸入輸出樣例】

輸入:
exam4.in
82363983742
3
輸出:
exam4.out
2170

【分析】
動態規劃,類似於『NOIP2000 乘積最大』。
狀態設定:
F[i,j] :前i個數添加j個乘號的最小和
Num[i,j]:原數中第i個數到第j個數組成的新數。
邊界狀態:F[i,0]=Num[1,i]
狀態轉移方程: F[i,j]=Min{F[k,j-1]+Num[k+1,i]}
目標狀態:F[N,K]
由於數據比較大,所以需要高精度計算。

【我的代碼】
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
const int SIZE=201;
int K;
int N;
typedef unsigned short int usint;
struct hugeint
{
 usint len,num[SIZE];
};
hugeint Num[201][201];
hugeint F[201][21];
void print(hugeint a)
{
 int i;
 for (i=a.len;i>=1;i--)
  printf("%d",a.num[i]);
 printf("\n");
}
hugeint add(hugeint a,hugeint b)
{
 int i;
 hugeint ans;
 memset(ans.num,0,sizeof(ans.num));
 if (a.len>b.len)
  ans.len=a.len;
 else
  ans.len=b.len;
 for (i=1;i<=ans.len;i++)
 {
  ans.num[i]+=(a.num[i]+b.num[i]);
  ans.num[i+1]+=ans.num[i]/10;
  ans.num[i]%=10;
 }
 if (ans.num[ans.len+1]>0)
  ans.len++;
 return ans;
}
bool over(hugeint a,hugeint b)
{
 int i;
 if (a.len<b.len)
  return false;
 if (a.len>b.len)
  return true;
 for (i=a.len;i>=1;i--)
 {
  if (a.num[i]<b.num[i])
   return false;
  if (a.num[i]>b.num[i])
   return true;
 }
 return false;
}
void init()
{
 hugeint tmp;
 memset(tmp.num,0,sizeof(tmp.num));
 char str[201];
 scanf("%s\n%d\n",&str,&K);
 int len=strlen(str);
 tmp.len=len;
 N=len;
 for (int i=0;i<len;i++)
 {
  tmp.num[i+1]=str[i]-'0';
 }
 for (int i=1;i<=len;i++)
 {
  for (int j=i;j<=len;j++)
  {
   memset(Num[i][j].num,0,sizeof(Num[i][j].num));
   Num[i][j].len=j-i+1;
   int top=Num[i][j].len;
   for (int k=i;k<=j;k++)
   {
    Num[i][j].num[top]=tmp.num[k];
    top--;
   }
   /*
   printf("%d %d %d ",i,j,Num[i][j].len);
   print(Num[i][j]);
   */
  }
 }
}
void dynamic()
{
 for (int i=1;i<=N;i++)
  F[i][0]=Num[1][i];
 for (int j=1;j<=K;j++)
 {
  for (int i=1;i<=N;i++)
  {
   for (int k=1;k<=N;k++)
    F[i][j].num[k]=9;
   F[i][j].len=N;
   for (int k=1;k<=i-1;k++)
   {
    hugeint temp=add(F[k][j-1],Num[k+1][i]);
    if(over(F[i][j],temp) )
    {
     F[i][j]=temp;
    }
   }
  }
 }
 print(F[N][K]);
}
int main()
{
 freopen("exam4.in","r",stdin);
 freopen("exam4.out","w",stdout);
 init();
 dynamic();
 return 0;
}

2011年12月11日 星期日

[動態規劃]OI練習題:乘法問題 [chf] 解題報告


【問題描述】
設有一個長度為 N 的數字字元串,分成 K+1 個部分,使得 K+1 個部 分的乘積最大。 例如 N=6 ,且數字字元串為 ‘ 310143 ‘ , K=3. 此時可能有的情況有以 下各種:
3 * 1 * 0 * 143=0
3 * 1 * 01 * 43=129
3 * 1 * 014 * 3=126
3 * 10 * 1 * 43=1290
3 * 10 * 14 * 3=1260
3 * 101 * 4 * 3=3636
31 * 0 * 1 * 43=0
31 * 01 * 4 * 3=372
310 * 1 * 4 * 3=3720
問題:當 N ,數字串, K 給出之後,找出一種分法使其乘積最大。
【輸入格式】
輸入由兩行組成,第一行有兩個整數,n(1≤n≤30)、k(1≤n≤30);n表示數字串長度、k表示乘號

個數。第二行是數字串。
【輸出格式】
輸出為一個整數,為乘積最大值。
【輸入樣例】
輸入文件名:chf.in
9 4
321044105
輸出文件名:chf.out
5166000
【分析】
動態規劃,和『NOIP2001 乘積最大』一樣。
狀態設定:
F[i,j]:前i個數字添加j個乘號時的最大值。
Num[i,j]:第i的數到第j個的數組成的數,可以在DP前用一個O(N^2)的預處理求出。
狀態轉移方程:
F[i,j]=Max(F[k,j-1]*Num[k+1][i])  (1<=k<=i-1)
目標狀態:  F[N,K]
時間複雜度:O(2*N^2)

【我的代碼】


#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; typedef long long LL; LL N,K; LL num[100][100]; LL F[100][100];   LL Max(LL a,LL b) { if (a>=b) return a; return b; }   LL myatoi(char *str) { LL ret=0; LL sign=1; if(*str=='-') sign=-1; else ret=ret*10+(*str-'0'); str++;   while(*str!= '\0') { ret=ret*10+(*str-'0'); str++; } return sign*ret; }   void init() { cin>>N>>K; char Temp[100]; cin>>Temp; char tmp[100]; for (unsigned int i=1;i<=strlen(Temp);i++) { for (unsigned int j=i;j<=strlen(Temp);j++) { unsigned int ti=i-1; unsigned int tj=j-1; memset(tmp,'\0',sizeof(tmp)); for (unsigned int k=ti;k<=tj;k++) tmp[k-ti]=Temp[k]; num[i][j]=myatoi(tmp); } } }   void dp() { for (int i=1;i<=N;i++) F[i][0]=num[1][i]; for (int j=1;j<=K;j++) { for (int i=1;i<=N;i++) { F[i][j]=0; for (int k=1;k<=i-1;k++) F[i][j]=Max(F[i][j],F[k][j-1]*num[k+1][i]); } } cout<<F[N][K]<<endl; }   int main() { freopen("chf.in","r",stdin); freopen("chf.out","w",stdout); init(); dp(); return 0; }

2011年11月25日 星期五

[動態規劃]USACO Nov07 Silver :Milking Time 擠奶時間(milkprod) 解題報告

譯 By CmYkRgB123
描述
貝茜是一隻非常努力工作的奶牛,她總是專注於提高自己的產量。爲了產更多的奶,她預計好了接下來的N (1 ≤ N ≤ 1,000,000)個小時,標記爲0..N-1。
Farmer John 計劃好了 M (1 ≤ M ≤ 1,000) 個可以擠奶的時間段。每個時間段有一個開始時間(0 ≤ 開始時間 ≤ N), 和一個結束時間 (開始時間 < 結束時間 ≤ N), 和一個產量 (1 ≤ 產量 ≤ 1,000,000) 表示可以從貝茜擠奶的數量。Farmer John 從分別從開始時間擠奶,到結束時間爲止。每次擠奶必須使用整個時間段。
但即使是貝茜也有她的產量限制。每次擠奶以後,她必須休息 R (1 ≤ R ≤ N) 個小時才能下次擠奶。給定Farmer John 計劃的時間段,請你算出在 N 個小時內,最大的擠奶的量。
輸入
  • 第 1 行: 三個整數 N, M, R
  • 第 2..M+1 行: 第 i+1 行 每行三個整數,爲每個時間段的開始時間、結束時間、產量
輸出
  • 第 1 行:一個整數 在 N 個小時內,最大的擠奶的量Farmer John放入擠奶計劃,開始時間,結束時間,產量。
樣例輸入
12 4 2
1 2 8
10 12 19
3 6 24
7 10 31
樣例輸出
43


【分析】
線性動態規劃。
由於題目中說每個擠奶時間段的結束時間都小於等於N,所以我們可以把每個擠奶時間段的結束時間加上R,可以在不影響結果的情況下為DP提供方便。

接著對擠奶時間段以每個時間段的開始時間為關鍵字進行快速排序。
狀態設定:
    V[i]:排序後第i個區間的產量
    S[i]:排序後第i個區間的開始時間
    E[i]:排序後第i個區間的結束時間+R
    F[i]:對於前i個時間段,在結束時間小於 第i個時間段的結束時間(即E[i])時 所獲得的最大擠奶產量。

邊界條件:
    F[0]=0
 狀態轉移方程:
    F[i]=max{F[j]}+V[i] (1≤j≤i-1,E[j]≤S[i])
目標結果:
   F[i]=max{F[i]}

【我的代碼】 
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
class MILK
{
public:
    int S;
    int E;
    int V;
}P[1001];
int F[1001];
int N,M,R;

int cmp(const void *a,const void *b)
{
    class MILK *c=(class MILK *)a;
    class MILK *d=(class MILK *)b;
    return c->S-d->S;
}

int Max(int a,int b)
{
    if(b>a)
        a=b;
    return a;
}

void init()
{
    scanf("%d %d %d\n",&N,&M,&R);
    for (int i=1;i<=M;i++)
    {
        scanf("%d %d %d\n",&P[i].S,&P[i].E,&P[i].V);
        P[i].E+=R;
    }
    qsort(P+1,M,sizeof(MILK),cmp);
}

void dynamic()
{
    F[0]=0;
    int Maxn=0;
    for (int i=1;i<=M;i++)
    {
        Maxn=0;
        for (int j=1;j<=i-1;j++)
        {
            if(P[j].E<=P[i].S)
            {
                Maxn=Max(Maxn,F[j]);
            }
        }
        Maxn+=P[i].V;
        F[i]=Maxn;
    }
   
    Maxn=0;
    for (int i=1;i<=M;i++)
    {
        Maxn=Max(Maxn,F[i]);
    }
    printf("%d\n",Maxn);
}

int main()
{
    freopen("milkprod.in","r",stdin);
    freopen("milkprod.out","w",stdout);
    init();
    dynamic();
    return 0;
}

 

2011年11月10日 星期四

[動態規劃]BYVoid魔獸世界模擬題 Stage.1 靈魂分流藥劑 soultap 解題報告

【問題描述】
幽暗城皇家鍊金師赫布瑞姆剛剛發明瞭一種用來折磨戰俘的新型藥 劑,這種藥劑被稱爲靈魂分流藥劑。靈魂分流藥劑的妙處在於能夠給戰俘帶來巨大的痛苦,但是卻不會讓戰俘死去。這種藥劑中包含了一些治療的成分,所以即使戰 俘想自盡,也會被救活。用這種求生不得,求死不能的感覺,來對付反對希爾瓦娜斯女王的狂徒們,實在是太美妙了。當然,靈魂分流藥劑要限定在一個用量範圍之 內,過少會達不到效果,而過多會直接殺了戰俘。
最近,我們抓獲了一個來自暴風城的探子,他掌握了我們的許多重要情報。希爾瓦娜斯女王命令你用最痛苦的手段折磨他。你從你的導師,靈魂分流藥劑的發明者——皇家鍊金師赫布瑞姆那裏獲得了N瓶藥劑。每瓶按照藥性的不同裝在M個箱子中。每瓶藥劑都有一個規格:對服用者造成的肉體傷害w,對服用者造成的意志折磨v,所屬的箱子t,和對服用者造成的痛苦值p。
據我們測試,那個暴風城探子的生命值爲A,意志力爲B。你要從每個箱子中最多拿取1瓶藥劑餵給他。注意,餵給他的藥劑造成的總肉體傷害不能超過他的生命值A,否則他會死去,總意志折磨不能超過他的意志力B,否則他會精神崩潰,我們沒有必要給一個精神崩潰的傻瓜製造那麼多痛苦。在不讓他死去或者精神崩潰的前提下,你要儘可能多的給他製造痛苦,你能解決這個問題嗎?
輸入格式
第1行:四個整數N,M,A,B,M個箱子的編號爲1..M。
第2行至第N+1行:第i+1行四個整數w,v,t,p表示第i瓶藥劑的肉體傷害,意志折磨,所屬箱子的編號,和造成的痛苦值。
輸出格式
第1行:一個整數,表示能夠造成的最大的痛苦值。
樣例輸入
5 3 20 20
5 10 1 200
10 5 1 100
8 11 2 56
10 10 2 50
5 5 3 100
樣例輸出
300
數據規模
對於30%的數據
N<=30
M<=5
對於100%的數據
N<=100
M<=10
A,B<=100

【分析】
經典的動態規劃,0/1背包問題。
以每個箱子為階段劃分狀態,而每個箱子又是一個最優子問題。

狀態設定
Box[i].W[j]:第i個箱子中第j件物品的肉體傷害
Box[i].V[j]:第i個箱子中第j件物品的意志折磨
Box[i].P[j]:第i個箱子中第j件物品的傷害值
Box[i].num:第i個箱子中 藥劑的總數
F[k][i][j] :對於前k個箱子,當探子生命值為i,意志力為j時的最大傷害值

邊界條件:
F[0][i][j]=0

狀態轉移方程:
F[k][i][j]= Max{ Max{F[k-1][i-Box[k].W[m]][j-Box[k].V[m]]+Box[k].P[m]} , F[k-1][i][j] }  (1<=m<=Box[k].num)

目標狀態:
F[M][A][B]
【我的代碼】
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
int F[11][101][101];

class BOX
{
public:
    int num;
    int W[101];
    int V[101];
    int P[101];
    BOX()
    {
        num=0;
    }
}Box[11];
int N,M;
int A,B;


void init()
{
    scanf("%d %d %d %d\n",&N,&M,&A,&B);
    int w,v,t,p;
    for (int i=1;i<=N;i++)
    {
        scanf("%d %d %d %d\n",&w,&v,&t,&p);
        Box[t].num++;
        Box[t].W[Box[t].num]=w;
        Box[t].V[Box[t].num]=v;
        Box[t].P[Box[t].num]=p;
    }
    return;
}

void dynamic()
{
    int tmp;
    for (int i=1;i<=A;i++)
        for (int j=1;j<=B;j++)
                F[0][i][j]=0;
       
    for (int k=1;k<=M;k++)
    {
        for(int i=1;i<=A;i++)
        {
            for (int j=1;j<=B;j++)
            {
                int Max=0;
                for (int m=1;m<=Box[k].num;m++)
                {
                    if(i-Box[k].W[m]>=0 && j-Box[k].V[m]>=0)
                    {
                        tmp=F[k-1][i-Box[k].W[m]][j-Box[k].V[m]]+Box[k].P[m];
                        if(tmp>Max)
                            Max=tmp;
                    }
                }
                if (F[k-1][i][j]>Max)
                    Max=F[k-1][i][j];
                F[k][i][j]=Max;
            }
        }
    }
    printf("%d\n",F[M][A][B]);
}

int main()
{
    freopen("soultap.in","r",stdin);
    freopen("soultap.out","w",stdout);
    init();
    dynamic();
    return 0;
}

【評測結果】
正在连接评测机...

已连接到评测机
GRID 1
名称 Flitty
系统版本 1.00
备注 COGS 1号评测机 Flitty
正在编译...
编译成功

测试点 结果 得分 运行时间 内存使用 退出代码
1 正确 10 0.000 s 724 KB 0
2 正确 10 0.006 s 724 KB 0
3 正确 10 0.001 s 724 KB 0
4 正确 10 0.001 s 724 KB 0
5 正确 10 0.005 s 724 KB 0
6 正确 10 0.006 s 724 KB 0
7 正确 10 0.006 s 724 KB 0
8 正确 10 0.006 s 724 KB 0
9 正确 10 0.006 s 724 KB 0
10 正确 10 0.006 s 724 KB 0
运行完成
运行时间 0.042 s
平均内存使用 724 KB
测试点通过状况 AAAAAAAAAA
得分:100
恭喜你通过了全部测试点!

[動態規劃]USACO Mar08 遊蕩的奶牛 ctravel 解題報告

【題目描述】
奶牛們在被劃分成N行M列(2 <= N <= 100; 2 <= M <= 100)的草地上遊走,試圖找到整塊草地中最美味的牧草。Farmer John在某個時刻看見貝茜在位置(R1, C1),恰好T (0 < T <= 15)秒後,FJ又在位置(R2, C2)與貝茜撞了正着。FJ並不知道在這T秒內貝茜是否曾經到過(R2, C2),他能確定的只是,現在貝茜在那裏。
設S爲奶牛在T秒內從(R1, C1)走到(R2, C2)所能選擇的路徑總數,FJ希望有一個程序來幫他計算這個值。每一秒內,奶牛會水平或垂直地移動1單位距離(奶牛總是在移動,不會在某秒內停在它上一 秒所在的點)。草地上的某些地方有樹,自然,奶牛不能走到樹所在的位置,也不會走出草地。
現在你拿到了一張整塊草地的地形圖,其中'.'表示平坦的草地,'*'表示擋路的樹。你的任務是計算出,一頭在T秒內從(R1, C1)移動到(R2, C2)的奶牛可能經過的路徑有哪些。
程序名: ctravel
輸入格式:
  • 第1行: 3個用空格隔開的整數:N,M,T
  • 第2..N+1行: 第i+1行爲M個連續的字符,描述了草地第i行各點的情況,保證字符是'.'和'*'中的一個
  • 第N+2行: 4個用空格隔開的整數:R1,C1,R2,以及C2
輸入樣例 (ctravel.in):
4 5 6
...*.
...*.
.....
.....
1 3 1 5
輸入說明:
草地被劃分成4行5列,奶牛在6秒內從第1行第3列走到了第1行第5列。
輸出格式:
  • 第1行: 輸出S,含義如題中所述
輸出樣例 (ctravel.out):
1
輸出說明:
奶牛在6秒內從(1,3)走到(1,5)的方法只有一種(繞過她面前的樹)。

【分析】
動態規劃。可以用加法原理,這和”過河卒“類似,動態規劃中並不作決策。

狀態設定
F[k][i][j]:前 k秒 走到(i,j)的路徑數。
G[i][j]=1( (i,j)是草地 ),0((i,j)是樹)

邊界條件:
F[0][R1][C1]=1;

狀態轉移方程:
F[k][i][j]+=Sum{F[k-1][i+1][j]*G[i+1][j],F[k-1][i][j+1]*G[i][j+1],F[k-1][i-1][j]*G[i-1][j],F[k-1][i][j-1]*G[i][j-1]}

目標狀態:
F[T][R2][C2]

【我的代碼】
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
int F[16][101][101];
int G[101][101];
int N,M,T;
int R1,C1;
int R2,C2;

void init()
{
    scanf("%d %d %d\n",&N,&M,&T);
    char c;
    for(int i=1;i<=N;i++)
    {
        for (int j=1;j<=M;j++)
        {
            if(j==M)
                scanf("%c\n",&c);
            else
                scanf("%c",&c);
            if(c=='.')
                G[i][j]=1;
            else
                G[i][j]=0;
        }
    }
    scanf("%d %d %d %d",&R1,&C1,&R2,&C2);
    F[0][R1][C1]=1;
}

void dynamic()
{
    int k=0;
    for (k=1;k<=T;k++)
    {
        for (int i=1;i<=N;i++)
        {
            for (int j=1;j<=M;j++)
            {
                if(!G[i][j])
                    continue;
                F[k][i][j]+=F[k-1][i+1][j]*G[i+1][j];
                F[k][i][j]+=F[k-1][i][j+1]*G[i][j+1];
                F[k][i][j]+=F[k-1][i-1][j]*G[i-1][j];
                F[k][i][j]+=F[k-1][i][j-1]*G[i][j-1];
            }
        }
    }
    printf("%d\n",F[T][R2][C2]);
}

int main()
{
    freopen("ctravel.in","r",stdin);
    freopen("ctravel.out","w",stdout);
    init();
    dynamic();
    return 0;
}

評測結果:
正在连接评测机...

已连接到评测机
GRID 1
名称 Flitty
系统版本 1.00
备注 COGS 1号评测机 Flitty
正在编译...
编译成功

测试点 结果 得分 运行时间 内存使用 退出代码
1 正确 10 0.014 s 948 KB 0
2 正确 10 0.002 s 948 KB 0
3 正确 10 0.001 s 948 KB 0
4 正确 10 0.001 s 948 KB 0
5 正确 10 0.007 s 948 KB 0
6 正确 10 0.001 s 948 KB 0
7 正确 10 0.004 s 948 KB 0
8 正确 10 0.001 s 948 KB 0
9 正确 10 0.006 s 948 KB 0
10 正确 10 0.004 s 948 KB 0
运行完成
运行时间 0.040 s
平均内存使用 568 KB
测试点通过状况 AAAAAAAAAA
得分:100
恭喜你通过了全部测试点!