目錄:
T1:反射
T2:自動匹配
T3:道路阻塞
T4:密碼編碼
全是Farmer Jonh與奶牛題,看來出題人很喜歡USACO
正題:
T1:反射
題目描述
農夫約翰把他的很多鏡子遺落在房子外面,他的奶牛們對這些鏡子很好奇,於是奶牛們把這些鏡子偷了!
奶牛們把鏡子放在了一個N*M的矩陣中,在每個小方格中,他們將鏡子按正對角線或者反對角線的方式放置,也就是說鏡子的放置形狀要麼是’/’,要麼是’\’。
某一天晚上,奶牛貝里斯拿着一個手電筒站在矩陣的外面,他打開手電筒按水平或者垂直方向朝矩陣內的鏡子照射,由於鏡子是對角線或者反對角線放置的,所以如果垂直的光過來的話,反射出來的光就是水平的,反之也是同樣的道理。貝里斯想要知道他從外面照過來的光最多能被鏡子反射幾次。
輸入
第一行是兩個正整數N和M,表示矩陣的大小。
接下里N行,每行M個字符,表示矩陣內鏡子放置的情況。字符是’/’或者’\’。
輸出
輸出一個整數,表示從外面照射進來的一束光最多能在矩陣內被反射的次數,如果會被反射無限次,就輸出-1。
樣例輸入
3 3
/\\
\\\
/\/
樣例輸出
3
分析:
分行、列枚舉鏡子反射的每種情況,用f表示當前的方向,方向用1.2.3.4代替,然後判斷一些不合法。
還有很玄學的一點:不用判斷 -1輸出。
CODE:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
char a[1001][1001];
int ans,maxx,n,m;
int f=0,f2=0;
int main()
{
freopen("mirror.in","r",stdin);
freopen("mirror.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j];
for(int i=1;i<=n;i+=n-1)
for(int j=1;j<=m;j++)
{
if(i==1) f=1; //方向
else f=3;
ans=0;
int x=i,y=j;
while(i==i) //行
{
f2=f;
if(a[x][y]=='/'&&f==1&&y>=1) y--,f=4; //鏡子每種情況,再改變方向
else if(a[x][y]=='/'&&f==2&&x>=1) x--,f=3;
else if(a[x][y]=='/'&&f==3&&y<=m) y++,f=2;
else if(a[x][y]=='/'&&f==4&&x<=n) x++,f=1;
else if(a[x][y]!='/'&&f==1&&y<=m) y++,f=2;
else if(a[x][y]!='/'&&f==2&&x<=n) x++,f=1;
else if(a[x][y]!='/'&&f==3&&y>=1) y--,f=4;
else if(a[x][y]!='/'&&f==4&&x>=1) x--,f=3;
else break;
if(f2!=f) ans++;
else break;
if(x<1||y<1||x>n||y>m) break;
}
if (ans>maxx) maxx=ans;
}
for(int j=1;j<=m;j+=m-1)
for(int i=1;i<=n;i++)
{
if(j==1) f=2;
else f=4;
ans=0;
int x=i,y=j;
while(i==i) //列
{
f2=f;
if(a[x][y]=='/'&&f==1&&y>=1) y--,f=4;
else if(a[x][y]=='/'&&f==2&&x>=1) x--,f=3;
else if(a[x][y]=='/'&&f==3&&y<=m) y++,f=2; //一樣的操作
else if(a[x][y]=='/'&&f==4&&x<=n) x++,f=1;
else if(a[x][y]!='/'&&f==1&&y<=m) y++,f=2;
else if(a[x][y]!='/'&&f==2&&x<=n) x++,f=1;
else if(a[x][y]!='/'&&f==3&&y>=1) y--,f=4;
else if(a[x][y]!='/'&&f==4&&x>=1) x--,f=3;
else break;
if(x<1||y<1||x>n||y>m) break;
}
if(ans>maxx) maxx=ans;
}
printf("%d",maxx);
}
T2:自動匹配
題目描述
奶牛貝里斯最近有了一部新手機,於是他經常發短信。但是他經常打錯單詞,因爲手機屏幕太小而他的爪子太大了((⊙o⊙))。農夫約翰決定幫助貝里斯來開發一個app應用,使得可以從一個不完整的單詞猜想整個單詞。
App應用是由W個單詞組成的,每個單詞都是由’a’…’z’組成的,這些單詞總的長度不超過1000000。現在,總共有N個不完整的單詞,每個單詞的度不超過1000。對於第i個不完整的單詞S_i,app應用要計算出在單詞庫中,按字典序排列的第K_i個前綴是S_i的單詞。注意,自己也是自己的前綴。
輸入
第一行是兩個正整數W和N。
接下來W行,每行一個字典庫裏的單詞。
接下里N行,每行一個K_i和其對應的不完整的單詞S_i。
輸出
輸出包括N行,對於第i行,輸出在字典庫中按字典序排列的滿足前綴是S_i的第K_i個單詞在原字典庫中的位置。如果沒有足夠的單詞,就輸出-1。
樣例輸入
10 3
dab
ba
ab
daa
aa
aaa
aab
abc
ac
dadba
4 a
2 da
4 da
樣例輸出
3
1
-1
分析:
這道題就是字符串處理以及快排+二分查找,用stl的二分查找函數:
lower_bound()就可以把代碼簡化得特別短。
CODE:
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
string z,name[30001];
int w,n,x;
struct node{
string name;
int place; //存奶牛信息
}s[30001];
bool cmp(node x,node y)
{
return x.name<y.name;
}
int main()
{
freopen("auto.in","r",stdin);
freopen("auto.out","w",stdout);
scanf("%d%d\n",&w,&n);
for (int i=1;i<=w;i++)
{
cin>>s[i].name;
s[i].place=i; //記錄位置
}
sort(s+1,s+1+w,cmp); //快排
for(int i=1;i<=w;i++) name[i]=s[i].name;
for(int i=1;i<=n;i++)
{
cin>>x>>z;
int u=lower_bound(name+1,name+1+w,z)-name; //stl二分查找函數
//二分查找name數組裏z首次出現的下標
u=u+x-1;
if(u>w) {
cout<<"-1";
continue;
}
if(!name[u].find(z,0)) printf("%d\n",s[u].place); //題目要求直接輸出位置
else cout<<"-1";
}
return 0;
}
T3:道路阻塞
題目描述
每天早上,約翰都要從他的家裏步行去農場,他途中可能要經過其他的一些地方。我們把這些地方和路抽象成一張圖,這張圖裏有N個點,共有M條邊(每條邊都是雙向邊),每條邊都有一個長度,約翰的家在第1個點,農場在第N個點,兩個點之間沒有重複的邊,並且這個圖是一個連通圖,每次約翰從家裏到農場總會選一條最短的路徑走。
但是約翰的奶牛們老是給約翰搗亂,奶牛們計劃在其中某條路上放一些乾草堆來阻礙約翰的行走,乾草堆放在哪條路上,那條邊的長度就相當於增加了一倍。現在,奶牛們想要知道如何選擇一條邊放乾草堆,才能使約翰從家裏到農場花費的路程增加最多。
輸入
第一行是兩個正整數N和M。
接下來M行,每行三個整數a,b,c表示點a到點b的距離是c。
輸出
輸出從家裏到農場的最短路徑最多會增加的距離。
樣例輸入
5 7
2 1 5
1 3 1
3 2 8
3 5 7
3 4 3
2 4 7
4 5 2
樣例輸出
2
分析:
這道題就是最短路,用spfa即可。
奶牛們會搗亂,也就是把某一條最短路的距離翻倍,所以我們每次求最短路的時候都乘2,取最大值。
全部做完後再把每條最短路除2,也就是還原就可以了。
CODE:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int m,n,k,x[25001],y[25001],a[251][251];
int f[1001000],dis[251],v[251],begin,end;
int spfa(){ //spfa,跑最短路
memset(dis,1,sizeof(dis));
memset(v,0,sizeof(v));
dis[1]=0;
v[1]=1;
f[1]=1;
int head=0,tail=1;
while(head<=tail){
head++;
int res=f[head];
for(int i=1;i<=n;i++){
if(a[res][i]!=0&&dis[i]>dis[res]+a[res][i]){
dis[i]=dis[res]+a[res][i];
if(v[i]!=1){
v[i]=1;
tail++;
f[tail]=i;
}
}
}
v[res]=0;
}
return dis[n]; //注意有返回值
}
int main(){
freopen("rblock.in","r",stdin);
freopen("rblock.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>x[i]>>y[i]>>k;
a[x[i]][y[i]]=k; //賦權值
a[y[i]][x[i]]=k;
}
begin=spfa();
for(int i=1;i<=m;i++){
a[x[i]][y[i]]*=2; //每次*2,奶牛搗亂
a[y[i]][x[i]]*=2;
end=max(spfa()-begin,end); //取最大值
a[x[i]][y[i]]/=2; //再還原
a[y[i]][x[i]]/=2;
}
cout<<end;
return 0;
}
T4:密碼編碼
題目描述
農夫約翰最近想發一些祕密的信息,但是他不想讓奶牛們知道。這些信息是‘A’到’Z’的字符組成的,長度至少是2。
爲了對這些信息進行加密,農夫約翰對這些信息進行了一系列的操作,每次操作,約翰把字符串S去掉從第一個開始連續的若干個字符或者從最後一個字符開始連續若干個字符(至少去掉一個字符,也不能全部去掉),然後把剩餘的字符串添加到原來S串的左邊或者右邊。例如,對於字符串ABC,一次操作可以有8種結果:
AABC
ABABC
BCABC
CABC
ABCA
ABCAB
ABCBC
ABCC
現在給定最後加密好的字符串,約翰想要知道這個字符串可能由多少種方法加密而來,注意,AAA可以由AA通過四種加密操作得來,雖然產生的AAA是一樣的,但是加密的過程是不一樣的我們就認爲是不同的方法。
輸入
一個字符串。
輸出
輸出這個加密的字符串可以由多少種方法加密而來。【答案要mod 2014】
樣例輸入
ABABA
樣例輸出
8
分析:
這道題要用遞歸,然後還要用到什麼dev-c++自帶函數:
substr??好像是個複製子字符串的玄學東西??
小朋友你是否有很多問號?
dalao講解時我直接疑惑,我做出來就馬上補博客……