您的位置:首页 > 其它

cf 的gym里的题目2016-2017 CT S03E03:

2017-06-09 12:16 211 查看
B:给一个网格,里面有黑色也有白色,每次反转一个黑色会将其相邻的4个格子与其同时反转(黑to白/白to黑),问最小能把全部格子翻成白色要求的步数,如果无法那么输出

"Damaged billboard",前不久刚做这个类型的题目,首先显然得出每个格子先反转和后反转并不影响,反转的次数1与3意义是相同的。那么直接枚举第一行的所有反转情况,然后由于第一行的反转情况可知,那么可以从第二行开始判断是否用反转。如第一行第一个是黑色,那么第二行第一个必定需要反转,因为目前只剩下其可以将第一行第一个的颜色给改变。第一行第二个如果是黑色,那么第二行第二个必须反转才有可能将全部变成白色,如果其是白色,那么必须不能反转第二行第二个,因为没有再能改变第一行第二个颜色的格子了,依次类推,每次这个格子是否反转是根据其上一行的颜色来判断,有可能其是白色但还是反转了,判断到最后一行最后一个的时候,除了最后一行其他格子全部为白色了,此时只需要判断最后一行是否全部为白色就可以判断这种方法是否可行了,然后在可行解中找最小反转次数即可。

wa1 没考虑最初全部为白色的情况,只需要反转0次。

#include <iostream>
#include <stdio.h>
#include <queue>
#include <string.h>
#include <stdlib.h>
#include <set>
#include <algorithm>
#include <map>
using namespace std;
int qq[20][20];
int fan[20][20];
int q1[20][20];
char map1[20][20];
int r,c;
int fun1(int x){
if(x==1)
return 0;
else return 1;
}
int fun2(int r,int c){
int t1=fan[r-1][c]+fan[r-2][c]+fan[r-1][c-1]+fan[r-1][c+1]+qq[r-1][c];
return t1;
}
int fun(int t1){
int i,j;
for(i=2;i<=r;i++)
for(j=1;j<=c;j++)
if(fun2(i,j)%2==1){
fan[i][j]=1;
t1++;
}else{
fan[i][j]=0;
}
int t2=0;
for(j=1;j<=c;j++)
if(fun2(r+1,j)%2==1)t2=1;
if(t2==1)return 0;
else return t1;
}
int main(){
int i,j,k,f1,f2,f3,f4,t1,t2,t3,t4;
//freopen("in.txt","r",stdin);
while(scanf("%d %d",&r,&c)==2&&(r||c)){
memset(qq,0,sizeof(qq));
memset(map1,0,sizeof(map1));
f4=0;
for(i=1;i<=r;i++){
for(j=1;j<=c;j++){
cin >> map1[i][j];
if(map1[i][j]=='\0'||map1[i][j]=='\n'){
j--;continue;
}
if(map1[i][j]=='X'){
f4=1;qq[i][j]=1; //X表示需要变成0
}else qq[i][j]=0;
}
}
t2=1e9+7;
memset(fan,0,sizeof(fan));
memset(q1,0,sizeof(q1));
for(i=0;i<1<<c;i++){
t1=0;
for(j=0;j<c;j++){
if(i>>j&1){
fan[1][c-j]=1;
t1++;
}else{
fan[1][c-j]=0;
}
}
t3=fun(t1);
if(t3&&t3<t2){
t2=t3;
}
}
if(t2==1e9+7&&f4)
cout <<"Damaged billboard."<<endl;
else{
if(f4==0)
t2=0;
cout <<"You have to tap "<< t2<<" tiles." <<endl;
}
}
return 0;
}
K.我写这题写得很大的败笔,写了特别久,代码能力还是太弱了。

K题是给一个图,图中有钥匙和门,起点和终点,有4种,每个门对应一种钥匙,一把钥匙可以开无数次这种门,问达到终点最近需要多少步。

直接bfs即可,walked多一维度记录状态,也就是最短走到这个地方所拥有的钥匙数。

important :状态的表示,加一个状态应该用s|1<<i而不是s|4这样的形式,状态用1,2,3,表示即可。

wa n次  每个函数都需要有返回值,基本其返回1才成立的if中,如果不成立也是需要return 0的 不然会可能出现wa

#include <iostream>
#include <stdio.h>
#include <queue>
#include <string.h>
#include <stdlib.h>
#include <set>
#include <algorithm>
#include <map>
using namespace std;
char map1[120][120];
struct ttt{
int r,c,s,k;
};
int dr[4]={0,1,-1,0};
int dc[4]={1,0,0,-1};
int walked[105][105][60];
int fun1(char b){
if(b=='B'||b=='Y'||b=='R'||b=='G')return 1;
else if(b=='b'||b=='y'||b=='r'||b=='g')return 2;
else return 0;
}
int fun2(char b){
if(b=='B'||b=='b')
return 1;
else if(b=='y'||b=='Y')
return 2;
else if(b=='R'||b=='r')
return 3;
else if(b=='G'||b=='g')
return 4;
}
int main(){
int i,j,k,f1,f2,f3,f4,t1,t2,t3,t4;
int r,c;
//freopen("in.txt","r",stdin);
//freopen("out2.txt","w",stdout);
t4=0;
while(scanf("%d %d",&r,&c)==2&&(r||c)){
memset(map1,0,sizeof(map1));
ttt s1,e1;
f2=0;
for(i=1;i<=r;i++)
for(j=1;j<=c;j++)
for(k=0;k<=(1<<5);k++)
walked[i][j][k]=1e9+7;
for(i=1;i<=r;i++)
for(j=1;j<=c;j++){
cin >> map1[i][j];
if(map1[i][j]=='\0'||map1[i][j]=='\n'){
j--;continue;
}
if(map1[i][j]=='*'){
s1.r=i;s1.c=j;
}else if(map1[i][j]=='X'){
f2=1;
}
}
if(f2==0){
cout << "The poor student is trapped!"<<endl;continue;
}
s1.s=0;s1.k=0;
walked[s1.r][s1.c][s1.k]=0;
queue<ttt>qq;
while(!qq.empty())qq.pop();
qq.push(s1);
ttt u,v;
int min1=1e9+7;
while(!qq.empty()){
u=qq.front();qq.pop();
if(map1[u.r][u.c]=='X'){
min1=u.s;
break;
}
v=u;
v.s++;
for(i=0;i<4;i++){
v.r=u.r+dr[i];
v.c=u.c+dc[i];
if(v.r>=1&&v.r<=r&&v.c>=1&&v.c<=c&&
map1[v.r][v.c]!='#'){
if(fun1(map1[v.r][v.c])==1){
t2=fun2(map1[v.r][v.c]);
if((v.k>>t2&1)&&v.s<walked[v.r][v.c][v.k]){
walked[v.r][v.c][v.k]=v.s;
qq.push(v);
}
}else if(fun1(map1[v.r][v.c])==2){
t2=fun2(map1[v.r][v.c]);
e1=v;e1.k=(e1.k|1<<t2);
if(e1.s<walked[v.r][v.c][e1.k]){
walked[v.r][v.c][e1.k]=e1.s;
qq.push(e1);
}
}else if(v.s<walked[v.r][v.c][v.k]){
walked[v.r][v.c][v.k]=v.s;
qq.push(v);
}
}
}
}if(min1!=1e9+7){
cout <<"Escape possible in "<<min1<<" steps."<< endl;
}else{
cout << "The poor student is trapped!"<<endl;
}
}
return 0;
}


N是给一个-R进制数,让转换为十进制,或者给一个十进制数,让转换为R进制数字。

转换的方法是这样

对于17024由八进制转换为10进制数

1*(-8)^4 +7*(-8)^3 +0*(-8)^2 +2*(-8)^1 +4*(-8)^0  = 1*4096+7*512+2*8+4*1 = 7700

也就是转换的时候如果位数是奇数,那么是乘-。

因为数字的性质,显然高位的+1比低位+任何都是大的。如对于转换15成-2进制

可以把各个位数上如果选择是的正数字都加上,找到第一个大于15的数字,然后再向右边减,如果遇到奇位,大于其,那么就-,也就是这个位子是1,如果遇到偶数位,因为之前计算的时候已经先把其算上了,如果大于其,那么其就是0,如果小于其,表明不能减去这个偶数位,其就为1.,可能比较难理解,看代码理解会清晰些。

如果转换-15为-2进制也是一样的逻辑。

把各个位上如果加上为负的都加上,直到第一个小于-15的数字,然后向右一一判断是否需要取这个位。

#include <iostream>
#include <stdio.h>
#include <queue>
#include <string.h>
#include <stdlib.h>
#include <set>
#include <algorithm>
#include <map>
#include <math.h>
using namespace std;
char s1[20];
char s2[5000];
int qq[5000];
int power(int x,int y){
if(y==0)return 1;
else{
int    t1=1;
for(int i=1;i<=y;i++)
t1*=x;
return t1;
}
}
int fun1(int x,int y){
int i=0,t1=0,f1=1,t2;
while(t1<x){
if(i%2==0){

4000
t2=power(y,i);
t1=t1+t2;
}
f1++;
if(f1==y){
i++;f1=1;
}
}
if(f1==1)i--;
memset(qq,0,sizeof(qq));
int t3=i;
if(f1!=1)
qq[i]=f1-1;
else
qq[i]=y-1;
t1-=x;i--;
while(i>=0){
if(i%2==0){ //是在加部分要还是不要
t2=0;
while((t2+1)*power(y,i)<=t1){
t2++;}
t1-=t2*power(y,i);
qq[i]=y-1-t2; //如果一个不减去说明全部都要
}else{
t2=0;
while((t2+1)*power(y,i)<=t1){
t2++;}
t1-=t2*power(y,i);
qq[i]=t2;
}
i--;
}
return t3;
}
int fun2(int x,int y){
int i=0,t1=0,f1=1,t2;
while(t1<x){
if(i%2==1){
t2=power(y,i);
t1=t1+t2;
}
f1++;
if(f1==y){
i++;f1=1;
}
}
if(f1==1)i--;
memset(qq,0,sizeof(qq));
int t3=i;
if(f1!=1)
qq[i]=f1-1;
else
qq[i]=y-1;
t1-=x;i--;
while(i>=0){
if(i%2==1){ //是在加部分要还是不要
t2=0;
while((t2+1)*power(y,i)<=t1){
t2++;}
t1-=t2*power(y,i);
qq[i]=y-1-t2; //如果一个不减去说明全部都要
}else{
t2=0;
while((t2+1)*power(y,i)<=t1){
t2++;}
t1-=t2*power(y,i);
qq[i]=t2;
}
i--;
}
return t3;
}
int fun3(int y){
int l1=strlen(s2);
int t3=0;
for(int i=0;i<l1;i++){
if((l1-i-1)%2==0)
t3+=(s2[i]-'0')*power(y,l1-i-1);
else
t3-=(s2[i]-'0')*power(y,l1-i-1);
}
return t3;
}
int main(){
int i,j,k,f1,f2,f3,f4,t1,t2,t3,t4;
int r,c;
// freopen("in.txt","r",stdin);
while(scanf("%s",&s1)==1){
if(s1[0]=='e')break;
if(s1[0]=='t'){
if(s1[3]=='1')
t1=10;
else
t1=s1[3]-'0';
cin >> t2;
if(t2==0){
cout <<"0"<<endl;
continue;
}
if(t2>0){
t3=fun1(t2,t1); //t1进制的t2
for(i=t3;i>=0;i--)
cout <<qq[i];
cout <<endl;
}else{
t2=-t2;
t3=fun2(t2,t1);
for(i=t3;i>=0;i--)
cout <<qq[i];
cout <<endl;
}
}else{
if(s1[5]=='1')
t1=10;
else
t1=s1[5]-'0';
cin >>s2;
t3=fun3(t1);
cout << t3<< endl;
}
}
return 0;
}


wa 2发给pow,系统的pow真的不靠谱,如果要使用就自己写一个power,系统的power涉及浮点数,不一定会正确。

R为模拟题,自己敲代码的速度还是太慢了,脑子别发呆,尽量跟上!!!

Y题是签到,Z就是找规律

 总结:系统的pow不可用,函数的返回值要有,即便返回一个0也是重要的,不然可能会wa,二进制加入一个数到集合中应该是S|1<<i,而不是S|i
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐