【問題描述】
Tom 是調皮的孩子,特別喜歡玩火,現在他手上有若干根長度分別爲 1 和sqrt(2)
的木棍,還有一張不能燃燒的平板,他把平板劃分成長度爲 1
的單元格,並標上座標。然後按以下規則把平板上的木棍組成一個連通圖:木棍的兩端必須放在單元格的頂點上。即長度爲 1
的木棍放在單元格的某一邊上,長度爲sqrt(2) 的木棍放在單元格的對角綫上。
Tom 的點火規則是,只能從木棍的兩端點火,而不能從木棍的中間點火。 如圖 ,不能在 A 點點火,但在 C 點或 B 點點火都是充許的。點火後,火會沿着木棍向前燃燒(每根都有自己的燃燒速度),並能點燃與它相接的其它木棍。
任務: 寫一程序計算從哪裏開始點火,使得燃燒的總時間最短,輸出最短時間。
Input Data
輸入文件第一行爲一個正整數 N ,表示組成圖形的木棍數目,後面共有 N 行,每行 5 個數: X1 Y1 X2 Y2 T , 其中( X1
, Y1 ) 和( X2 , Y2 )分別表示木棍兩端的座標, T 表示木棍燃燒時間,是指從木棍的某一端點火燃燒到別一端,燃完所需的時間。
Output Data
輸出文件是一個保留 4 位小數的實數,表示所有木棍完全燃燒的最少時間。
約束
1 ≤n≤40
保證圖形是連通的,所有的木棍長度都是 1 或sqrt(2) ,沒有任何兩根木棍重合 .
-200≤ X1, Y1, X2, Y2 ≤200; 0≤ T ≤ 10^7 .
如果你的輸出結果與標準答案相差小於 0.001 ,則認爲你的結果正確。
樣例 1
fire.in
1
0 0 1 1 1
fire.out
1.0000
解釋:從任一端點火都行,燃燒時間都是 1
樣例 2
fire.in5
0 0 0 1 1
1 0 0 1 10
0 0 1 0 1
0 0 1 1 1
2 2 1 1 1
fire.out
3.2500
解釋:在 (0,0) 位置點火
木棍 1, 3 和 4 將被點燃,燃燒 0.5 分鐘後,木棍 2 將被從中間點燃向兩端燃燒,再過 0.5 分鐘,木棍 1, 3, 4 將被完全燃燒,木棍 5 將被點燃並在 1 分鐘後燃燒完 ( 比木棍 2 早燃完 ) 。
木棍 2 從中間向兩端燃燒 0.5 分鐘以後,變成兩小段,每段的燃燒時間是 4.5 分鐘。但因爲此時兩小段木棍的另一端也同時被點燃,燃燒速度變成原來的兩倍,還需 2.25 分鐘的燃燒時間, 所以總時間: 1 + 2 . 25 = 3 . 25
樣例 3
fire.in3
1 1 1 2 10
1 2 2 2 10
1 1 2 2 50
fire.out
35.0000
解釋:在 (1,2) 位置點火, 木棍 (1 1, 1 2) 和 (1 2, 2 2) 將燃燒 10 分鐘。 . 最後一根木棍在 10 分鐘後從兩端被點燃,燃燒時間爲 25 分鐘。
【分析】
Floyd算法求最短路,只是構圖很困難罷了。
具體算法的PPT課件下載:http://zhuyifan.net84.net/ppt/fire.ppt
【我的代碼】
/*
*Problem: 燃燒木棍 fire
*Author: Yee-fan Zhu
*Date: Dec.01.2011
*Website: www.zyfworks.tk
*/
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
int N;
double max(double x,double y)
{
if(y>x)
x=y;
return x;
}
class Wood
{
public:
double x1,x2;
double y1,y2;
double time;
}F[42];
class Point
{
public:
double x,y;
}P[1000];
Wood W[1000];
int D=0;
int M=0;
double Mat[1002][1002];
int Used[2000][2000];
const int add=500;
void init()
{
std::ios::sync_with_stdio(false);
scanf("%d\n",&N);
for (int i=-450;i<=1050;i++)
for (int j=-450;j<=1050;j++)
Used[i+add][j+add]=-1;
for (int i=1;i<=300;i++)
for (int j=1;j<=300;j++)
Mat[i][j]=10000000;
for (int i=1;i<=300;i++)
Mat[i][i]=0;
for (int i=1;i<=N;i++)
{
scanf("%lf %lf %lf %lf %lf\n",&F[i].x1,&F[i].y1,&F[i].x2,&F[i].y2,&F[i].time);
}
double x1,x2,y1,y2,t;
for (int i=1;i<=N;i++)
{
x1=F[i].x1,y1=F[i].y1;
x2=F[i].x2,y2=F[i].y2;
t=F[i].time;
int p1,p2;
p1=Used[int(x1*2)+add][int(y1*2)+add];
p2=Used[int(x2*2)+add][int(y2*2)+add];
if(p1==-1)
{
M++;
Used[int(x1*2)+add][int(y1*2)+add]=M;
P[M].x=x1,P[M].y=y1;
p1=M;
}
if(p2==-1)
{
M++;
Used[int(x2*2)+add][int(y2*2)+add]=M;
P[M].x=x2,P[M].y=y2;
p2=M;
}
Mat[p1][p2]=t;
Mat[p2][p1]=t;
bool flag=true;
if(F[i].x1-F[i].x2==0 || F[i].y1-F[i].y2==0)
{
D++;
W[D].x1=x1,W[D].y1=y1;
W[D].x2=x2,W[D].y2=y2;
W[D].time=t;
continue;
}
double x3,y3;
double x4,y4;
if((x1>x2 && y1>y2 )||(x1<x2 && y1<y2 ))
{
if(x1>x2 && y1>y2 )
{
x3=x1-1;
y3=y1;
x4=x1;
y4=y1-1;
}
if(x1<x2 && y1<y2)
{
x3=x1;
y3=y1+1;
x4=x1+1;
y4=y1;
}
}
else
{
if(x1<x2 && y1>y2)
{
x3=x1;
y3=y1-1;
x4=x1+1;
y4=y1;
}
if(x1>x2 && y1<y2)
{
x3=x1-1;
y3=y1;
x4=x1;
y4=y1+1;
}
}
for (int j=1;j<=N;j++)
{
if((F[j].x1==x3 && F[j].y1==y3 && F[j].x2==x4 &&F[j].y2==y4) || (F[j].x1==x4 && F[j].y1==y4 && F[j].x2==x3 &&F[j].y2==y3) )
{
double x5,y5;
x5=double((x1+x2)/double(2));
y5=double((y1+y2)/double(2));
int p3=Used[int(x5*2)+add][int(y5*2)+add];
if(p3==-1)
{
M++;
p3=M;
P[M].x=x5,P[M].y=y5;
Used[int(x5*2)+add][int(y5*2)+add]=M;
}
Mat[p3][p1]=t/(double(2)),Mat[p1][p3]=t/(double(2));
Mat[p2][p3]=t/(double(2)),Mat[p2][p3]=t/(double(2));
D++;
W[D].x1=x3,W[D].y1=y3;
W[D].x2=x5,W[D].y2=y5;
W[D].time=t/(double(2));
D++;
W[D].x1=x4,W[D].y1=y4;
W[D].x2=x5,W[D].y2=y5;
W[D].time=t/(double(2));
flag=false;
break;
}
}
if(flag)
{
D++;
W[D].x1=x1,W[D].y1=y1;
W[D].x2=x2,W[D].y2=y2;
W[D].time=t;
}
}
}
void Floyd()
{
double tmp;
for (int k=1;k<=M;k++)
{
for (int i=1;i<=M;i++)
{
for (int j=1;j<=M;j++)
{
tmp=Mat[i][k]+Mat[k][j];
if(tmp<Mat[i][j])
Mat[i][j]=tmp;
}
}
}
}
void work()
{
double tot=100000000;
for (int i=1;i<=M;i++)
{
double x,y;
x=P[i].x;
y=P[i].y;
int tmp;
tmp=int(x*2);
if(tmp%2!=0)
continue;
int p=Used[int(x*2)+add][int(y*2)+add];
double s=0;
for (int j=1;j<=M;j++)
s=max(s,Mat[p][j]);
double x1,x2;
double y1,y2;
int p1,p2;
double t1,t2;
double dif;
double need;
for (int j=1;j<=D;j++)
{
x1=W[j].x1,y1=W[j].y1;
x2=W[j].x2,y2=W[j].y2;
p1=Used[int(x1*2)+add][int(y1*2)+add];
p2=Used[int(x2*2)+add][int(y2*2)+add];
t1=Mat[p][p1];
t2=Mat[p][p2];
double mint=t2;
if(t1<mint)
mint=t1;
dif=max(t1-t2,t2-t1);
if(dif>=W[j].time)
continue;
need=(W[j].time-dif)/(double(2));
need=need+mint+dif;
if(need>s)
s=need;
}
if(s<tot)
tot=s;
}
printf("%.4lf",tot);
}
int main()
{
freopen("firez.in","r",stdin);
freopen("firez.out","w",stdout);
init();
Floyd();
work();
return 0;
}
2011年12月1日 星期四
2011年11月28日 星期一
GZOI2011廣州NOI省選:簡易計算器 calculator 解題報告
【問題描述】相信大家都用過計算器,一般來說,計算機都可以計算簡單的加、減、乘、除這幾種運算。簡易計算器的功能和一般的計算器一樣,只是它更加簡單,只能處理整數運算,也就是說,它沒有小數點按鈕,並且它的除法運算是整除運算。現在,我們給出簡易計算器上的按鈕序列,請你編程序,模擬簡易計算器的功能,輸出最終的結果。
【計算器組成】簡易計算器由以下按鈕組成:數字按鈕: 0 1 2 3 4 5 6 7 8 9運算按鈕: + - * /等於號按鈕:=正負轉換按鈕:+/-為了表述方便,+/- 按鈕用 F 表示 ,
【計算器邏輯處理】
計算器內存有3個值,M1,M2,OP,STM1為計算器的左運算值,初始值為0M2為計算器的右運算值,初始值0OP為計算器的當前運算符,初始值為空ST為狀態標記,初始值為0
狀態裝換邏輯如下:
ST=0 (M1/OP輸入態):顯示值:M1
輸入數字N :M1=N ,轉 ST=1狀態
輸入F :M1=-M1,轉 ST=0狀態
輸入運算符:OP=運算符,轉ST=2狀態
輸入“=”:轉 ST=0狀態
ST=1 (M1+/OP輸入態):顯示值:M1
輸入數字N :如果M1>=0則 M1=M1*10+N 否則M1=M1*10-N;轉 ST=1狀態;
輸入F :M1=-M1,轉 ST=1狀態;
輸入運算符:OP=運算符,轉ST=2狀態
輸入“=”:轉 ST=0狀態
ST=2 (OP/M2輸入態):顯示值:M1
輸入數字N:M2=N,轉ST=3狀態;輸入F:M2=0,轉 ST=3狀態;
輸入運算符:OP=運算符,轉ST=2狀態
輸入“=”:
轉 ST=0狀態
ST=3 (M2+/OP輸入態):顯示值:M2
輸入數字N:如果M2>=0則 M2=M2*10+N 否則M2=M2*10-N;轉ST=3狀態;輸入F:M2=-M2,轉 ST=3狀態;
輸入運算符:M1=[M1][OP][M2] 的值OP=運算符;轉ST=2狀態
輸入“=”: M1=[M1][OP][M2] 的值轉ST=0狀態
【輸入格式】輸入只有一行,表示在計算器輸入的按鈕,長度<=100,裡面只包含如下字符 :0123456789+-*/=F輸入數據保證不會出現除以0的情況,運算過程中各個內存的值的範圍在[-10000000, 10000000] 以內
【輸出格式】
輸出包含一行整數,表示最後在計算器顯示的結果
【輸入樣例】
123=*2F-+/3+-=
【輸出樣例】
-82
【分析】
字符串處理題目,由於各種狀態之間的來回跳換,所以用遞歸實現比較方便。由於數據不大,暴力的遞歸不成問題。
時間複雜度:O(length)。
length表示字符串的長度。
【我的代碼】
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
char str[102];
int OP;
int top=0;
int M1=0,M2=0;
int show;
int len;
int tmp;
void deal0();
void deal1();
void deal2();
void deal3();
int Getop(char op)
{
if(op=='+')
return 1;
if(op=='-')
return 2;
if(op=='*')
return 3;
if(op=='/')
return 4;
if(op=='F')
return 5;
if(op=='=')
return 6;
return 0;
}
void check()
{
if(top==len)
{
printf("%d\n",show);
exit(0);
}
return;
}
void deal0()
{
show=M1;
check();
tmp=0;
if(Getop(str[top])==0)
{
while(Getop(str[top])==0 &&top<len)
{
tmp=tmp*10+str[top]-'0';
top++;
}
M1=tmp;
deal1();
return;
}
if(Getop(str[top])==5)
{
M1=-M1;
top++;
deal0();
return;
}
if(Getop(str[top])>=1 && Getop(str[top])<=4)
{
OP=Getop(str[top]);
top++;
deal2();
return;
}
if(Getop(str[top])==6)
{
top++;
deal0();
return;
}
}
void deal1()
{
show=M1;
check();
tmp=0;
if(Getop(str[top])==0)
{
while(Getop(str[top])==0 && top<len)
{
tmp=tmp*10+str[top]-'0';
top++;
}
if(M1>=0)
M1=M1*10+tmp;
else
M1=M1*10-tmp;
deal1();
return;
}
if(Getop(str[top])==5)
{
M1=-M1;
top++;
deal1();
return;
}
if(Getop(str[top])>=1 && Getop(str[top])<=4)
{
OP=Getop(str[top]);
top++;
deal2();
return;
}
if(Getop(str[top])==6)
{
top++;
deal0();
return;
}
}
void deal2()
{
show=M1;
check();
tmp=0;
if(Getop(str[top])==0)
{
while(Getop(str[top])==0 && top<len)
{
tmp=tmp*10+str[top]-'0';
top++;
}
M2=tmp;
deal3();
return;
}
if(Getop(str[top])==5)
{
M2=0;
top++;
deal3();
return;
}
if(Getop(str[top])>=1 && Getop(str[top])<=4)
{
OP=Getop(str[top]);
top++;
deal2();
return;
}
if(Getop(str[top])==6)
{
top++;
deal0();
return;
}
}
void deal3()
{
show=M2;
check();
tmp=0;
if(Getop(str[top])==0)
{
while(Getop(str[top])==0 && top<len)
{
tmp=tmp*10+str[top]-'0';
top++;
}
if(M2>=0)
M2=M2*10+tmp;
else
M2=M2*10-tmp;
deal3();
return;
}
if(Getop(str[top])==5)
{
M2=-M2;
top++;
deal3();
return;
}
if(Getop(str[top])>=1 && Getop(str[top])<=4)
{
if(OP==1)
M1=M1+M2;
if(OP==2)
M1=M1-M2;
if(OP==3)
M1=M1*M2;
if(OP==4)
M1=M1/M2;
OP=Getop(str[top]);
top++;
deal2();
return;
}
if(Getop(str[top])==6)
{
top++;
//deal0();
if(OP==1)
M1=M1+M2;
if(OP==2)
M1=M1-M2;
if(OP==3)
M1=M1*M2;
if(OP==4)
M1=M1/M2;
deal0();
return;
}
}
void init()
{
std::ios::sync_with_stdio(false);
scanf("%s\n",&str);
len=strlen(str);
return;
}
int main()
{
freopen("calculator.in","r",stdin);
freopen("calculator.out","w",stdout);
init();
deal0();
return 0;
}
【評測結果】
正在连接评测机...
已连接到评测机
正在编译...
编译成功
运行完成
运行时间 0.002 s
平均内存使用 275 KB
测试点通过状况 AAAAA
得分:100
恭喜你通过了全部测试点!
【計算器組成】簡易計算器由以下按鈕組成:數字按鈕: 0 1 2 3 4 5 6 7 8 9運算按鈕: + - * /等於號按鈕:=正負轉換按鈕:+/-為了表述方便,+/- 按鈕用 F 表示 ,
【計算器邏輯處理】
計算器內存有3個值,M1,M2,OP,STM1為計算器的左運算值,初始值為0M2為計算器的右運算值,初始值0OP為計算器的當前運算符,初始值為空ST為狀態標記,初始值為0
狀態裝換邏輯如下:
ST=0 (M1/OP輸入態):顯示值:M1
輸入數字N :M1=N ,轉 ST=1狀態
輸入F :M1=-M1,轉 ST=0狀態
輸入運算符:OP=運算符,轉ST=2狀態
輸入“=”:轉 ST=0狀態
ST=1 (M1+/OP輸入態):顯示值:M1
輸入數字N :如果M1>=0則 M1=M1*10+N 否則M1=M1*10-N;轉 ST=1狀態;
輸入F :M1=-M1,轉 ST=1狀態;
輸入運算符:OP=運算符,轉ST=2狀態
輸入“=”:轉 ST=0狀態
ST=2 (OP/M2輸入態):顯示值:M1
輸入數字N:M2=N,轉ST=3狀態;輸入F:M2=0,轉 ST=3狀態;
輸入運算符:OP=運算符,轉ST=2狀態
輸入“=”:
轉 ST=0狀態
ST=3 (M2+/OP輸入態):顯示值:M2
輸入數字N:如果M2>=0則 M2=M2*10+N 否則M2=M2*10-N;轉ST=3狀態;輸入F:M2=-M2,轉 ST=3狀態;
輸入運算符:M1=[M1][OP][M2] 的值OP=運算符;轉ST=2狀態
輸入“=”: M1=[M1][OP][M2] 的值轉ST=0狀態
【輸入格式】輸入只有一行,表示在計算器輸入的按鈕,長度<=100,裡面只包含如下字符 :0123456789+-*/=F輸入數據保證不會出現除以0的情況,運算過程中各個內存的值的範圍在[-10000000, 10000000] 以內
【輸出格式】
輸出包含一行整數,表示最後在計算器顯示的結果
【輸入樣例】
123=*2F-+/3+-=
【輸出樣例】
-82
【分析】
字符串處理題目,由於各種狀態之間的來回跳換,所以用遞歸實現比較方便。由於數據不大,暴力的遞歸不成問題。
時間複雜度:O(length)。
length表示字符串的長度。
【我的代碼】
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
char str[102];
int OP;
int top=0;
int M1=0,M2=0;
int show;
int len;
int tmp;
void deal0();
void deal1();
void deal2();
void deal3();
int Getop(char op)
{
if(op=='+')
return 1;
if(op=='-')
return 2;
if(op=='*')
return 3;
if(op=='/')
return 4;
if(op=='F')
return 5;
if(op=='=')
return 6;
return 0;
}
void check()
{
if(top==len)
{
printf("%d\n",show);
exit(0);
}
return;
}
void deal0()
{
show=M1;
check();
tmp=0;
if(Getop(str[top])==0)
{
while(Getop(str[top])==0 &&top<len)
{
tmp=tmp*10+str[top]-'0';
top++;
}
M1=tmp;
deal1();
return;
}
if(Getop(str[top])==5)
{
M1=-M1;
top++;
deal0();
return;
}
if(Getop(str[top])>=1 && Getop(str[top])<=4)
{
OP=Getop(str[top]);
top++;
deal2();
return;
}
if(Getop(str[top])==6)
{
top++;
deal0();
return;
}
}
void deal1()
{
show=M1;
check();
tmp=0;
if(Getop(str[top])==0)
{
while(Getop(str[top])==0 && top<len)
{
tmp=tmp*10+str[top]-'0';
top++;
}
if(M1>=0)
M1=M1*10+tmp;
else
M1=M1*10-tmp;
deal1();
return;
}
if(Getop(str[top])==5)
{
M1=-M1;
top++;
deal1();
return;
}
if(Getop(str[top])>=1 && Getop(str[top])<=4)
{
OP=Getop(str[top]);
top++;
deal2();
return;
}
if(Getop(str[top])==6)
{
top++;
deal0();
return;
}
}
void deal2()
{
show=M1;
check();
tmp=0;
if(Getop(str[top])==0)
{
while(Getop(str[top])==0 && top<len)
{
tmp=tmp*10+str[top]-'0';
top++;
}
M2=tmp;
deal3();
return;
}
if(Getop(str[top])==5)
{
M2=0;
top++;
deal3();
return;
}
if(Getop(str[top])>=1 && Getop(str[top])<=4)
{
OP=Getop(str[top]);
top++;
deal2();
return;
}
if(Getop(str[top])==6)
{
top++;
deal0();
return;
}
}
void deal3()
{
show=M2;
check();
tmp=0;
if(Getop(str[top])==0)
{
while(Getop(str[top])==0 && top<len)
{
tmp=tmp*10+str[top]-'0';
top++;
}
if(M2>=0)
M2=M2*10+tmp;
else
M2=M2*10-tmp;
deal3();
return;
}
if(Getop(str[top])==5)
{
M2=-M2;
top++;
deal3();
return;
}
if(Getop(str[top])>=1 && Getop(str[top])<=4)
{
if(OP==1)
M1=M1+M2;
if(OP==2)
M1=M1-M2;
if(OP==3)
M1=M1*M2;
if(OP==4)
M1=M1/M2;
OP=Getop(str[top]);
top++;
deal2();
return;
}
if(Getop(str[top])==6)
{
top++;
//deal0();
if(OP==1)
M1=M1+M2;
if(OP==2)
M1=M1-M2;
if(OP==3)
M1=M1*M2;
if(OP==4)
M1=M1/M2;
deal0();
return;
}
}
void init()
{
std::ios::sync_with_stdio(false);
scanf("%s\n",&str);
len=strlen(str);
return;
}
int main()
{
freopen("calculator.in","r",stdin);
freopen("calculator.out","w",stdout);
init();
deal0();
return 0;
}
【評測結果】
正在连接评测机...
已连接到评测机
GRID | 1 |
名称 | Flitty |
系统版本 | 1.00 |
备注 | COGS 1号评测机 Flitty |
编译成功
测试点 | 结果 | 得分 | 运行时间 | 内存使用 | 退出代码 |
1 | 正确 | 20 | 0.000 s | 275 KB | 0 |
2 | 正确 | 20 | 0.000 s | 275 KB | 0 |
3 | 正确 | 20 | 0.000 s | 275 KB | 0 |
4 | 正确 | 20 | 0.000 s | 275 KB | 0 |
5 | 正确 | 20 | 0.000 s | 275 KB | 0 |
运行时间 0.002 s
平均内存使用 275 KB
测试点通过状况 AAAAA
得分:100
恭喜你通过了全部测试点!
NOIP2011提高組 選擇客棧 hotel 解題報告
【問題描述】
麗江河邊有n 家很有特色的客棧,客棧按照其位置順序從1 到n 編號。每家客棧都按照某一種色調進行裝飾(總共k 種,用整數0 ~ k-1 表示),且每家客棧都設有一家咖啡店,每家咖啡店均有各自的最低消費。兩位遊客一起去麗江旅遊,他們喜歡相同的色調,又想嘗試兩個不同的客棧,因此決定分別住在色調相同的兩家客棧中。晚上,他們打算選擇一家咖啡店喝咖啡,要求咖啡店位於兩人住的兩家客棧之間(包括他們住的客棧),且咖啡店的最低消費不超過p。他們想知道總共有多少種選擇住宿的方案,保證晚上可以找到一家最低消費不超過p元的咖啡店小聚。
【輸入】輸入文件hotel.in,共n+1 行。第一行三個整數n,k,p,每兩個整數之間用一個空格隔開,分別表示客棧的個數,色調的數目和能接受的最低消費的最高值;接下來的n 行,第i+1 行兩個整數,之間用一個空格隔開,分別表示i 號客棧的裝飾色調和i 號客棧的咖啡店的最低消費。
【輸出】輸出文件名為hotel.out。輸出只有一行,一個整數,表示可選的住宿方案的總數。
【輸入輸出樣例1】
hotel.in
5 2 3
0 5
1 3
0 2
1 4
1 5
hotel.out
3
【輸入輸出樣例說明】
2人要住同樣色調的客棧,所有可選的住宿方案包括:住客棧①③,②④,②⑤,④⑤,但是若選擇住4、5 號客棧的話,4、5 號客棧之間的咖啡店的最低消費是4,而兩人能承受的最低消費是3 元,所以不滿足要求。因此只有前3 種方案可選。
【數據范圍】
對於30%的數據,有n≤100;
對於50%的數據,有n≤1,000;
對於100%的數據,有2≤n≤200,000,0<k≤50,0≤p≤100, 0≤最低消費≤100。
【分析】
記憶化枚舉,或者動態規劃。
可以邊讀入邊計算:
Pre[i]:前i個客棧中,最後一個 消費小於P的客棧。
Sum[i,j]:前j個客棧中,第i種顔色的總數量。
S:總方案數
定義ci,pi表示讀入時第i個客棧的顔色、價格。
Sum[ci,i]=Sum[ci,i-1]+1;
Sum[j,i]=Sum[j-1,i](j!=ci)
如果pi<=P,Pre[i]=Pre[i-1]+1,S+=Sum[ci][Pre[i]]-1。
如果pi>P,Pre[i]=Pre[i-1],S+=Sum[ci][Pre[i]]。
最後輸出S即可。沒有必要使用long long類型。
時間複雜度:O(NK)
空間複雜度:NK
【我的代碼】
【評測結果】
正在连接评测机...
已连接到评测机
正在编译...
编译成功
运行完成
运行时间 0.564 s
平均内存使用 41681 KB
测试点通过状况 AAAAAAAAAA
得分:100
恭喜你通过了全部测试点!
已完成数据库校验。
麗江河邊有n 家很有特色的客棧,客棧按照其位置順序從1 到n 編號。每家客棧都按照某一種色調進行裝飾(總共k 種,用整數0 ~ k-1 表示),且每家客棧都設有一家咖啡店,每家咖啡店均有各自的最低消費。兩位遊客一起去麗江旅遊,他們喜歡相同的色調,又想嘗試兩個不同的客棧,因此決定分別住在色調相同的兩家客棧中。晚上,他們打算選擇一家咖啡店喝咖啡,要求咖啡店位於兩人住的兩家客棧之間(包括他們住的客棧),且咖啡店的最低消費不超過p。他們想知道總共有多少種選擇住宿的方案,保證晚上可以找到一家最低消費不超過p元的咖啡店小聚。
【輸入】輸入文件hotel.in,共n+1 行。第一行三個整數n,k,p,每兩個整數之間用一個空格隔開,分別表示客棧的個數,色調的數目和能接受的最低消費的最高值;接下來的n 行,第i+1 行兩個整數,之間用一個空格隔開,分別表示i 號客棧的裝飾色調和i 號客棧的咖啡店的最低消費。
【輸出】輸出文件名為hotel.out。輸出只有一行,一個整數,表示可選的住宿方案的總數。
【輸入輸出樣例1】
hotel.in
5 2 3
0 5
1 3
0 2
1 4
1 5
hotel.out
3
【輸入輸出樣例說明】
客棧編號 |
① | ② | ③ | ④ | ⑤ |
色調 | 0 | 1 | 0 | 1 | 1 |
最低消費 | 5 | 3 | 2 | 4 | 5 |
【數據范圍】
對於30%的數據,有n≤100;
對於50%的數據,有n≤1,000;
對於100%的數據,有2≤n≤200,000,0<k≤50,0≤p≤100, 0≤最低消費≤100。
【分析】
記憶化枚舉,或者動態規劃。
可以邊讀入邊計算:
Pre[i]:前i個客棧中,最後一個 消費小於P的客棧。
Sum[i,j]:前j個客棧中,第i種顔色的總數量。
S:總方案數
定義ci,pi表示讀入時第i個客棧的顔色、價格。
Sum[ci,i]=Sum[ci,i-1]+1;
Sum[j,i]=Sum[j-1,i](j!=ci)
如果pi<=P,Pre[i]=Pre[i-1]+1,S+=Sum[ci][Pre[i]]-1。
如果pi>P,Pre[i]=Pre[i-1],S+=Sum[ci][Pre[i]]。
最後輸出S即可。沒有必要使用long long類型。
時間複雜度:O(NK)
空間複雜度:NK
【我的代碼】
C++语言: Codee#24285
01 /*
02 *Problem:NOIP2011-Senior-Hotel
03 *Date:2011.11.27
04 *Author:Yee-fan Zhu
05 */
06 #include <cstdio>
07 #include <cstdlib>
08 #include <iostream>
09 using namespace std;
10
11 const int MAXN=200002;
12 int Sum[52][MAXN];
13 int Pre[MAXN];
14 int S=0;
15 int N,P,K;
16
17 void init()
18 {
19 std::ios::sync_with_stdio(false);
20 scanf("%d %d %d\n",&N,&K,&P);
21
22 for (int i=0;i<=N;i++)
23 Pre[i]=0;
24 for (int i=0;i<=N;i++)
25 for (int j=0;j<=K;j++)
26 Sum[j][i]=0;
27
28 int c,p;
29 for (int i=1;i<=N;i++)
30 {
31 scanf("%d %d\n",&c,&p);
32 Sum[c][i]=Sum[c][i-1]+1;
33
34 for (int j=0;j<K;j++)
35 if(j!=c)
36 Sum[j][i]=Sum[j][i-1];
37
38 if(p<=P)
39 {
40 Pre[i]=i;
41 S+=Sum[c][Pre[i]]-1;
42 }
43 else
44 {
45 Pre[i]=Pre[i-1];
46 S+=Sum[c][Pre[i]];
47 }
48 }
49 printf("%d\n",S);
50 }
51
52 int main()
53 {
54 freopen("hotel.in","r",stdin);
55 freopen("hotel.out","w",stdout);
56 init();
57 return 0;
58 }
02 *Problem:NOIP2011-Senior-Hotel
03 *Date:2011.11.27
04 *Author:Yee-fan Zhu
05 */
06 #include <cstdio>
07 #include <cstdlib>
08 #include <iostream>
09 using namespace std;
10
11 const int MAXN=200002;
12 int Sum[52][MAXN];
13 int Pre[MAXN];
14 int S=0;
15 int N,P,K;
16
17 void init()
18 {
19 std::ios::sync_with_stdio(false);
20 scanf("%d %d %d\n",&N,&K,&P);
21
22 for (int i=0;i<=N;i++)
23 Pre[i]=0;
24 for (int i=0;i<=N;i++)
25 for (int j=0;j<=K;j++)
26 Sum[j][i]=0;
27
28 int c,p;
29 for (int i=1;i<=N;i++)
30 {
31 scanf("%d %d\n",&c,&p);
32 Sum[c][i]=Sum[c][i-1]+1;
33
34 for (int j=0;j<K;j++)
35 if(j!=c)
36 Sum[j][i]=Sum[j][i-1];
37
38 if(p<=P)
39 {
40 Pre[i]=i;
41 S+=Sum[c][Pre[i]]-1;
42 }
43 else
44 {
45 Pre[i]=Pre[i-1];
46 S+=Sum[c][Pre[i]];
47 }
48 }
49 printf("%d\n",S);
50 }
51
52 int main()
53 {
54 freopen("hotel.in","r",stdin);
55 freopen("hotel.out","w",stdout);
56 init();
57 return 0;
58 }
【評測結果】
正在连接评测机...
已连接到评测机
GRID | 1 |
名称 | Flitty |
系统版本 | 1.00 |
备注 | COGS 1号评测机 Flitty |
编译成功
测试点 | 结果 | 得分 | 运行时间 | 内存使用 | 退出代码 |
1 | 正确 | 10 | 0.000 s | 41681 KB | 0 |
2 | 正确 | 10 | 0.000 s | 41681 KB | 0 |
3 | 正确 | 10 | 0.000 s | 41681 KB | 0 |
4 | 正确 | 10 | 0.001 s | 41681 KB | 0 |
5 | 正确 | 10 | 0.001 s | 41681 KB | 0 |
6 | 正确 | 10 | 0.001 s | 41681 KB | 0 |
7 | 正确 | 10 | 0.054 s | 41681 KB | 0 |
8 | 正确 | 10 | 0.125 s | 41681 KB | 0 |
9 | 正确 | 10 | 0.192 s | 41681 KB | 0 |
10 | 正确 | 10 | 0.190 s | 41681 KB | 0 |
运行时间 0.564 s
平均内存使用 41681 KB
测试点通过状况 AAAAAAAAAA
得分:100
恭喜你通过了全部测试点!
已完成数据库校验。
2011年11月27日 星期日
NOIP2011_Day1 mayan:用程序解決mayan puzzle遊戲
NOIP2011一試的第三題給我介紹了一個好玩的智力遊戲——Mayan Puzzle。聯賽過後,我從網上下載了這個一夜間變得巨火的遊戲。
在遊戲中,第9關被用來當聯賽那題的說明,第14關就是輸入輸出樣例。
遊戲下載:英文原版、漢化版
首先先誇讚一下遊戲的開發人員,動畫效果做的不錯啊!
我在第8關就碰到了難題,一直過不了關,於是就用聯賽時寫的程序試了一下,結果很棒,程序總能找到正確的解決方案!於是從第8關到第45關都是我用程序解出來的~~
先貼上程序吧:
比如第10關,把它轉換為程序的輸入文件就是這樣:
mayan.in
3
1 2 2 0
2 0
1 0
3 1 3 0
1 3 1 0
運行程序,輸出文件是:
mayan.out
0 0 1
3 2 1
3 0 1
於是我按照程序的“指示”移動方塊,沒想到果然過關了!
在遊戲中,第9關被用來當聯賽那題的說明,第14關就是輸入輸出樣例。
遊戲下載:英文原版、漢化版
首先先誇讚一下遊戲的開發人員,動畫效果做的不錯啊!
我在第8關就碰到了難題,一直過不了關,於是就用聯賽時寫的程序試了一下,結果很棒,程序總能找到正確的解決方案!於是從第8關到第45關都是我用程序解出來的~~
先貼上程序吧:
C++语言: Codee#24246
//NOIP2011-Senior-mayan
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct aaa
{
int t[6];
int c[6][8];
aaa()
{
memset(t,0,sizeof(t));
memset(c,0,sizeof(c));
}
};
int n,ans[6][3];
bool flag,b[6][8];
aaa solve(aaa g)
{
aaa h;
int i,j;
for(i=1;i<=5;i++)
{
for(j=1;j<=g.t[i];j++)
{
if(g.c[i][j]&&!b[i][j])
{
h.t[i]++;
h.c[i][h.t[i]]=g.c[i][j];
}
}
}
return h;
}
aaa clear(aaa g)
{
int i,j;
aaa h;
flag=false;
memset(b,0,sizeof(b));
for(i=1;i<=5;i++)
{
for(j=1;j<=g.t[i];j++)
{
if(i<=3)
{
if(g.c[i][j]==g.c[i+1][j]&&g.c[i][j]==g.c[i+2][j])
{
b[i][j]=b[i+1][j]=b[i+2][j]=true;
flag=true;
}
}
if(j<=g.t[i]-2)
{
if(g.c[i][j]==g.c[i][j+1]&&g.c[i][j]==g.c[i][j+2])
{
b[i][j]=b[i][j+1]=b[i][j+2]=true;
flag=true;
}
}
}
}
if(flag)
{
h=solve(g);
return clear(h);
}
else
{
return g;
}
}
void output()
{
freopen("mayan.out","w",stdout);
int i;
for(i=1;i<=n;i++)
{
printf("%d %d %d\n",ans[i][0],ans[i][1],ans[i][2]);
}
exit(0);
}
void dfs(aaa g,int k)
{
int i,j,l;
aaa h;
flag=true;
for(i=1;i<=5;i++)
{
if(g.t[i])
{
flag=false;
break;
}
}
if(flag)
{
if(k>n)
{
output();
}
else
{
return;
}
}
if(k>n)
{
return;
}
for(i=1;i<=5;i++)
{
for(j=1;j<=g.t[i];j++)
{
if(i<5)
{
if(j>g.t[i+1])
{
h=g;
h.t[i+1]++;
h.c[i+1][h.t[i+1]]=h.c[i][j];
h.c[i][j]=0;
h.t[i]--;
for(l=j;l<=h.t[i];l++)
{
h.c[i][l]=h.c[i][l+1];
}
h=clear(h);
ans[k][0]=i-1;
ans[k][1]=j-1;
ans[k][2]=1;
dfs(h,k+1);
}
else
{
h=g;
l=h.c[i][j];
h.c[i][j]=h.c[i+1][j];
h.c[i+1][j]=l;
h=clear(h);
ans[k][0]=i-1;
ans[k][1]=j-1;
ans[k][2]=1;
dfs(h,k+1);
}
}
if(i>1)
{
if(j>g.t[i-1])
{
h=g;
h.t[i-1]++;
h.c[i-1][h.t[i-1]]=h.c[i][j];
h.c[i][j]=0;
h.t[i]--;
for(l=j;l<=h.t[i];l++)
{
h.c[i][l]=h.c[i][l+1];
}
h=clear(h);
ans[k][0]=i-1;
ans[k][1]=j-1;
ans[k][2]=-1;
dfs(h,k+1);
}
}
}
}
}
int main()
{
freopen("mayan.in","r",stdin);
freopen("mayan.out","w",stdout);
int i,j;
aaa g;
scanf("%d",&n);
for(i=1;i<=5;i++)
{
scanf("%d",&j);
while(j)
{
g.t[i]++;
g.c[i][g.t[i]]=j;
scanf("%d",&j);
}
}
dfs(g,1);
printf("-1\n");
return 0;
}
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct aaa
{
int t[6];
int c[6][8];
aaa()
{
memset(t,0,sizeof(t));
memset(c,0,sizeof(c));
}
};
int n,ans[6][3];
bool flag,b[6][8];
aaa solve(aaa g)
{
aaa h;
int i,j;
for(i=1;i<=5;i++)
{
for(j=1;j<=g.t[i];j++)
{
if(g.c[i][j]&&!b[i][j])
{
h.t[i]++;
h.c[i][h.t[i]]=g.c[i][j];
}
}
}
return h;
}
aaa clear(aaa g)
{
int i,j;
aaa h;
flag=false;
memset(b,0,sizeof(b));
for(i=1;i<=5;i++)
{
for(j=1;j<=g.t[i];j++)
{
if(i<=3)
{
if(g.c[i][j]==g.c[i+1][j]&&g.c[i][j]==g.c[i+2][j])
{
b[i][j]=b[i+1][j]=b[i+2][j]=true;
flag=true;
}
}
if(j<=g.t[i]-2)
{
if(g.c[i][j]==g.c[i][j+1]&&g.c[i][j]==g.c[i][j+2])
{
b[i][j]=b[i][j+1]=b[i][j+2]=true;
flag=true;
}
}
}
}
if(flag)
{
h=solve(g);
return clear(h);
}
else
{
return g;
}
}
void output()
{
freopen("mayan.out","w",stdout);
int i;
for(i=1;i<=n;i++)
{
printf("%d %d %d\n",ans[i][0],ans[i][1],ans[i][2]);
}
exit(0);
}
void dfs(aaa g,int k)
{
int i,j,l;
aaa h;
flag=true;
for(i=1;i<=5;i++)
{
if(g.t[i])
{
flag=false;
break;
}
}
if(flag)
{
if(k>n)
{
output();
}
else
{
return;
}
}
if(k>n)
{
return;
}
for(i=1;i<=5;i++)
{
for(j=1;j<=g.t[i];j++)
{
if(i<5)
{
if(j>g.t[i+1])
{
h=g;
h.t[i+1]++;
h.c[i+1][h.t[i+1]]=h.c[i][j];
h.c[i][j]=0;
h.t[i]--;
for(l=j;l<=h.t[i];l++)
{
h.c[i][l]=h.c[i][l+1];
}
h=clear(h);
ans[k][0]=i-1;
ans[k][1]=j-1;
ans[k][2]=1;
dfs(h,k+1);
}
else
{
h=g;
l=h.c[i][j];
h.c[i][j]=h.c[i+1][j];
h.c[i+1][j]=l;
h=clear(h);
ans[k][0]=i-1;
ans[k][1]=j-1;
ans[k][2]=1;
dfs(h,k+1);
}
}
if(i>1)
{
if(j>g.t[i-1])
{
h=g;
h.t[i-1]++;
h.c[i-1][h.t[i-1]]=h.c[i][j];
h.c[i][j]=0;
h.t[i]--;
for(l=j;l<=h.t[i];l++)
{
h.c[i][l]=h.c[i][l+1];
}
h=clear(h);
ans[k][0]=i-1;
ans[k][1]=j-1;
ans[k][2]=-1;
dfs(h,k+1);
}
}
}
}
}
int main()
{
freopen("mayan.in","r",stdin);
freopen("mayan.out","w",stdout);
int i,j;
aaa g;
scanf("%d",&n);
for(i=1;i<=5;i++)
{
scanf("%d",&j);
while(j)
{
g.t[i]++;
g.c[i][g.t[i]]=j;
scanf("%d",&j);
}
}
dfs(g,1);
printf("-1\n");
return 0;
}
比如第10關,把它轉換為程序的輸入文件就是這樣:
mayan.in
3
1 2 2 0
2 0
1 0
3 1 3 0
1 3 1 0
運行程序,輸出文件是:
mayan.out
0 0 1
3 2 1
3 0 1
於是我按照程序的“指示”移動方塊,沒想到果然過關了!
訂閱:
文章 (Atom)