PAT (Basic Level) Practice 1003 我要通過!(兩種解法)
乙級1003
這題和HOJ3788一樣,故把那邊的sample也拿過來:
題意好理解,就對條件3解釋一下:
如果 aPbTc 是正確的,那麼 aPbATca 也是正確的,其中 a、 b、 c 均或者是空字串,或者是僅由字母 A 組成的字串。
就相當於是先對aPbATca進行操作成aPbTc,這一個新的字串再對條件1、2、3判斷,對於這時候的條件3,aPbTc又是一個新的“aPbATca”,所以在條件3的操作方法一樣
先介紹一下自己頭次看到這題的想法,純暴力模擬原題
先排除其它情況
1.如果有PAT之外的字
2.如果P、T出現2次以上或者1次都沒出現+沒有A
3.如果T前面不是A(判斷P後面是不是A可能會有陣列溢位的危險)
4.字串長度不足3的
條件1,直接強行各元素一一對應就行
條件2,xPATx,也就是P左邊的A和T右邊的A數量一樣即可
條件3,先拿出aPbATca,要找到a,bA,ca的位置,這時候我們就有了分開來的這三個組合,將它重組成aPbTc就可以了,然後組成的aPbTc再進行條件1、2、3的判斷
純模擬,對字串的分解構成操作了很多,程式碼上有部分註釋 還算能理解
模擬題就是要注意如果出什麼樣例與結果不符了的話,要一步一步慢慢除錯,一個分號都不能打錯!
AC程式碼:
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; int is1(char *p,int len); int is2(char *p,int len); int is3(char *p,int len); int newlen; int main(){ int n; cin>>n; char pat[102]; while(n--){ scanf("%s",&pat); int len = strlen(pat); if(is1(pat,len)||is2(pat,len)||is3(pat,len)){ // printf("is1 = %d\n",is1(pat,len)); // printf("is2 = %d\n",is2(pat,len)); // printf("is3 = %d\n",is3(pat,len)); printf("YES\n"); }else printf("NO\n"); } return 0; } int is1(char *p,int len){ if(len==3){ if(p[0]=='P'&&p[1]=='A'&&p[2]=='T') return 1; } return 0; } int is2(char *p,int len){ int p_pos = 0; for(int i = 0;i<len;i++){ if(p[i]!='P'&&p[i]!='A'&&p[i]!='T') return 0; if(p[i]=='P'&&i+2<len&&p[i+1]=='A'&&p[i+2]=='T'){ p_pos = i; } } if(p_pos+p_pos+3!=len||p_pos == 0) return 0; for(int i = 0;i<p_pos;i++){ // printf("p[%d] = %c\n",i,p[i]); if(p[i]!='A') return 0; else{ if(p[i]!=p[i+p_pos+3]) return 0; } } return 1; } int is3(char *p,int len){//aPbATca --> aPbTc int p_pos=-1; int a_pos=-1; int t_pos=-1; int onlyt=0,onlyp=0; for(int i = 0;i<len;i++){ if(p[i]!='P'&&p[i]!='A'&&p[i]!='T') return 0; if(p[i]=='P'){//只有一個P if(onlyp){ return 0; } p_pos = i; onlyp = 1; } if(i>=1&&p[i]=='T'){//只有一個T if(onlyt){ return 0; } t_pos = i; onlyt = 1; if(p[i-1]=='A'){//T前面必須是A a_pos = i-1; }else return 0; //否則退出沒寫,一直卡著我的bug位置所在。。 } } if(p_pos==-1||a_pos==-1||t_pos==-1) return 0; newlen = a_pos+len-p_pos-t_pos; // printf("p_pos = %d a_pos = %d t_pos = %d newlen = %d\n",p_pos,a_pos,t_pos,newlen); char aPbTc[newlen]; int pos = 0; for(pos ; pos <= p_pos ; pos++){//aP aPbTc[pos] = p[pos]; // printf("p[pos] = %c\n",p[pos]); } int lenb = a_pos - p_pos - 1; // printf("a_pos = %d p_pos = %d lenb = %d \n",a_pos,p_pos,lenb); for(int i = 0;i<lenb;i++){ //aPbT aPbTc[pos] = 'A'; pos++; } aPbTc[pos++] = 'T'; int lenc = len - p_pos - t_pos - 1; // printf("lenc = %d\n",lenc); for(int i = 0;i<lenc;i++){ aPbTc[pos++] = 'A'; } // for(int i = 0 ;i<newlen;i++){ // printf("%c",aPbTc[i]); // } // cout<<endl; // printf("is1 = %d\n",is1(aPbTc,len)); // printf("is2 = %d\n",is2(aPbTc,len)); if(is1(aPbTc,newlen)||is2(aPbTc,newlen)||is3(aPbTc,newlen)){ return 1; } return 0; }
再講一下另一個思路:找規律
第一次看的時候看不出規律,第二次看的時候發現了……所以如果遇到一個非常複雜的模擬題可以先放一放,有可能這題會有特殊的規律
針對條件3,首先要明白aPbATca轉換成aPbTc後,這個新的字串也可能還是aPbATca的格式
然後針對這個操作再詳細思考一下:
我們從aPbATca轉換成aPbTc,實質上是去掉了b+A的一個A,以及c+a的一個a。
如果條件1、2不通過,繼續條件3下去,每次都是去掉b+A的一個A,c+a的一個a
去掉最後,肯定是以條件1和條件2為出口出去,那就是說,去掉最後肯定是
xPATx的格式(x=null即條件1)
再將其轉換成aPbTc,那就是此時我的B=一個A,a=c
然後往回推成aPbATca,最左邊的a不變,每一次b加一個A,c加一個a
推回到原字串,P和T之間我每加n個A,T後面的字串內容就是n*a
那就是說 只要我的a*b = c
AC程式碼:
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int p_pos = -1;
int t_pos = -1;
int a_pos = -1;
int isright(char *a,int len){//字串格式確認
int onlyp = 0;
int onlyt = 0;
for(int i = 0;i < len;i++){
if(a[i]!='P'&&a[i]!='A'&&a[i]!='T') return 0;
else{
if(a[i]=='P'){
if(onlyp) return 0;
else {onlyp = 1; p_pos = i;}
}
if(a[i]=='T'){
if(onlyt) return 0;
else {
onlyt = 1;
t_pos = i;
if(a[i-1]=='A') a_pos = i-1;
else return 0;
}
}
}
}
if(!onlyp||!onlyt) return 0;
return 1;
}
int main(){
int n;
cin>>n;
char pat[102];
while(n--){
scanf("%s",&pat);
int len = strlen(pat);
int wellplay = 0;
if(isright(pat,len)){
int lena = p_pos;
int lenb = a_pos - p_pos - 1;
int lenca = len - t_pos - 1;
int lenc = lenca - lena;
if(lenb*lena==lenc){
wellplay = 1;
}
}
if(wellplay)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}