题目见此处: http://blog.csdn.net/leizhehan/article/details/70492339
本蒟蒻膜拜无上学神zyk和lyb
(免责声明:如果你提交我的代码而不能通过的话,我不负任何责任;)
(数据截止至2017.4.23 10:00)
1.KPM的简单题
尝试人数 23
通过人数 23
通过率 100%
十分简单的一个高精度题目。(如果你不知道什么是高精度,请自行百度 http://baike.baidu.com/link?url=M-w5KoXet9NoFSXNIoithD0phumxgPeeJiLPbJxe2X1paNi-q95jzj5NQDE55RSJvVkBBVR-HpQnzHC5LuZPYv1FTn6FEvcA8mGgpAct-C279ojqKMt4o2UaRB9lJJdq )有几点需要注意:
1.认真读题目!认真读题目!!没有仔细看数据范围的我差点开了个unsigned long long!!
2.进位时的处理,这是让很多同学想了很久的地方。
3.数组应该开多大?2^64次方的数据大小,肯定小于10^64,两个数加起来也一定小于10^65,所以开100的数组就够了。
OK,第一题就这样。
(突然发现自己忘了贴代码)
#include<cstdio>
#include<cstring>
using namespace std;
char a1[10005],b1[10005];
int a[10005],b[10005],c[10005],i;
int main()
{
int t=10;
while(t--)
{
memset(a1,0,sizeof a1);
memset(b1,0,sizeof b1);
memset(a,0,sizeof a);
memset(b,0,sizeof b);
memset(c,0,sizeof c);
scanf("%s%s",a1,b1);
for(int i=0;i<strlen(a1);i++)a[i]=a1[strlen(a1)-i-1]-'0';
for(int i=0;i<strlen(b1);i++)b[i]=b1[strlen(b1)-i-1]-'0';
for(int i=0;i<10000;i++)c[i]=a[i]+b[i];
for(int i=1;i<9999;i++)
{
c[i]+=c[i-1]/10;
c[i-1]%=10;
}
for(i=10000;i>=1;i--)if(c[i]!=0)break;
for(;i>=0;i--)printf("%d",c[i]);
printf("\n");
}
return 0;
}
2.环保轨道1
尝试人数 19
通过人数 19
通过率 100%
这是一道最短路的题目。
首先,注意内存限制:131000kb。这说明可以开一个邻接矩阵(我很不喜欢邻接链表的好不好)。
提示:floyd会超时,但是,如果你真不会dijkstra/SPFA,你可以用它来骗骗分。
(在这里膜拜一下用SPFA的学圣)
有一点需要注意:若不能搭乘轨道到达,就不去宣传,也就是说最后加总的时候,dist数组里大于infinity的不能加(话说那个样例一点用都没有,根本看不出不去宣传时的情况)。
上代码:
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=1003;
const int inf=1<<29;
int t[maxn][maxn];
int I,J,n,m;
int a=75000;
int main()
{
for(int i=0;i<maxn;i++)
for(int j=0;j<maxn;j++)t[i][j]=inf;
cin>>n>>m;I=1;
for(int i=0;i<m;i++)
{
int x,y,c;
cin>>x>>y>>c;
t[x][y]=c;
}
int cur, minn=inf,dist[maxn];
for(int i=0;i<maxn;i++)dist[i]=inf;
bool tf[maxn];
for(int i=0;i<maxn;i++)tf[i]=false;
cur=I;tf[cur]=true;dist[cur]=0;
do
{
for(int i=1;i<maxn;i++)
if(!tf[i]&&t[cur][i]!=inf&&dist[i]>dist[cur]+t[cur][i])
dist[i]=dist[cur]+t[cur][i];
minn=inf;
for(int i=1;i<maxn;i++)
if(!tf[i]&&minn>dist[i]){minn=dist[i];cur=i;}
tf[cur]=true;
}while(a--);
double ans=0;
for(int i=2;i<=n;i++)if(dist[i]<inf)ans+=0.2*dist[i];
printf("%.1lf\n",ans);
return 0;
}
3.鸣人和佐助
尝试人数 17
通过人数 6
通过率 35%
这不就是暴力搜索吗?(此人已经被打死)
这是全卷最难的题目(废话),在这里膜一下通过的大神和蒟蒻:大神吴雨桐,大神quzhizhou,大神龙狙,大神Kesdiael Ken(zyk),天天打游戏只会骗分还和csz抢某某某的蒟蒻377isrubbish,大神0721林沛隆(lpl)。
好了,说一下正解思路吧。(请看代码中的注释)
哎,交了三次才过。
## 这是错误的代码!
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
using namespace std;
int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1},T=500000;
bool flag[205][205]={},tf=false;
char a[205][205];
struct node
{
int mx,my,t,time;
};
int main()
{
queue<node> q;
int mx,my,gx,gy,m,n,t,ans=-1;cin>>m>>n>>t;
memset(a,'.',sizeof a);
for(int i=1;i<=m;i++)
{
getchar();
for(int j=1;j<=n;j++)cin>>a[i][j];
}
for(mx=1;mx<=m;mx++)
{
for(my=1;my<=n;my++)if(a[mx][my]=='@')break;
if(my!=n+1)break;
}
for(gx=1;gx<=m;gx++)
{
for(gy=1;gy<=n;gy++)if(a[gx][gy]=='+')break;
if(gy!=n+1)break;
}
node first;
first.mx=mx;first.my=my;
first.t=t;first.time=0;
q.push(first);
while(T--&&!q.empty())
{
node last=q.front(),w;
q.pop();
flag[last.mx][last.my]=true;
if(last.mx==gx&&last.my==gy){ans=last.time;break;}
for(int i=0;i<4;i++)
{
if(flag[last.mx+dx[i]][last.my+dy[i]])continue;
if(a[last.mx+dx[i]][last.my+dy[i]]=='.')continue;
if(a[last.mx+dx[i]][last.my+dy[i]]=='*'||
a[last.mx+dx[i]][last.my+dy[i]]=='+'||a[last.mx+dx[i]][last.my+dy[i]]=='@')
{
w.mx=last.mx+dx[i];w.my=last.my+dy[i];
w.t=last.t;w.time=last.time+1;
q.push(w);
}
if(a[last.mx+dx[i]][last.my+dy[i]]=='#')
{
if(last.t>0)
{
w.mx=last.mx+dx[i];w.my=last.my+dy[i];
w.t=last.t-1;
w.time=last.time+1;
q.push(w);
}
else continue;
}
}
if(tf)break;
}
cout<<ans<<endl;
return 0;
}
当时写的时候犯下了许多错误:
1.一开始结构体里还传了二维数组,卡得要死。
2.那个T是什么?是我用来骗分的。
3.判断重复的数组没有加入查克拉能量,多次重复,导致出错。
正解代码:
//经过无数次的推翻再重写:
#include<cstdio>
#include<queue>//头文件
using namespace std;//命名空间
struct node{int HP,ans,x,y;};//单个节点的定义
queue<node>q;//广度优先搜索需要用到队列
int n,m,t,ox,oy,minx=9999999;//ox,oy是目标状态(佐助的位置)
bool v[201][201][11];//判断是否已经达到过的状态:第一,二维是x,y坐标,第三维是查克拉能量。
char c[201][201];//存储地图
int dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};//变化量(其实当时应该用const的)
int main()
{
scanf("%d%d%d",&n,&m,&t);//输入
node a,b,d;//a是最初状态,b是当前状态,d是即将入队的状态
for(int i=0;i<n;++i)
{
scanf("%s",c[i]);//单行字符读入
for(int j=0;j<m;++j)
if(c[i][j]=='@')
{
a.HP=t;
a.x=i;
a.y=j;
a.ans=0;
q.push(a);
}//找到鸣人的位置,更新数据,存储为a节点,推入队列
else if(c[i][j]=='+')
{
ox=i;
oy=j;
}//找到佐助的位置,存储为x,y坐标形式
}
while(!q.empty())//广度优先搜索算法核心语句
{
b=q.front();//取头
for(int i=0;i<4;++i)//从上,下,左,右四个方向依次判断
{
d=b;//d是即将入队的结构体
d.x+=dx[i];
d.y+=dy[i];//先行更新x,y坐标
if(d.x>=0&&d.x<n&&d.y>=0&&d.y<m)//判断是否为边缘
{
if(c[d.x][d.y]=='#')d.HP--;//如果为大蛇丸的手下
if(!v[d.x][d.y][d.HP]&&d.HP>=0)//如果没有到达过此状态并且还有查克拉
{
d.ans++;//时间增加
v[d.x][d.y][d.HP]=true;//标记为已经到达过
q.push(d);//入队
if(d.x==ox&&d.y==oy)
{
printf("%d\n",d.ans);
return 0;
}//判断是否到达了目标状态,如果是,输出答案,程序结束
}
}
}
q.pop();//上下左右均判断入队,弹出首个元素
}//在队列非空时继续执行
printf("-1\n");//如果没有找到目标状态,输出-1
return 0;//必须要加的一行
}//程序结束
改进了的部分在于:
1.刚才提到过的几点
2.判断是否在边缘,减少了在外面包围一圈其他字符的麻烦。
总结:
由这次考试可以看出:
要提高知识“水”平,要提高对信息之美的认识(语出lyb)(划掉划掉)
要积攒人品啊。