河畔镇是一个景色秀丽,气候宜人的度假胜地,每天都会有很多的游客来这里游玩。但奇怪的是这里总会出现一些潜伏者。果不其然,通过保卫者的跟踪,发现在河畔镇的地下隐藏着Blitz的秘密武器实验室。最危险的地方也是最安全的地方,这里人多,所以只能采用狙击作战,一场“无声无息“的战斗即刻打响。
每到周末小z,小y便开始在河畔军训小h(当然有时也会被反军训)。
不过他们军训采用刀战(即相遇时才可军训)
每当小z,小y,小h三人在河畔整相遇时,小z和小y便可军训小h
由于小h有兔耳朵buff加成,小h每秒最多可以移动3步,且可以选择上/下/左/右/左上/左下/右上/右下8个方向移动
小z,小y每秒均只能移动1步,只能上/下/左/右4个方向移动。
当然,三人均可选择保持原地不动。
三人移动始终在地图范围内。
下面,给你河畔的地图以及小z,小y,小h的初始坐标。
请你求出最快军训小h的时间(即3人相遇的最短时间),如果无法军训小h则输出“lack of junxun”
多组数据
每组数据第一行两个整数N,M(1<=N,M<=1000)代表河畔地图的行和列
接下来是N*M大小的地图
其中“z”,“y”,“h”分别代表小z,小y,小h的初始坐标
“#”代表障碍物,“.”表示可以正常通过的位置
对于每组数据
如果能军训小h,则输出最快军训小h所需的时间
否则,输出“lack of junxun”
2 4
z…h
#y#.
2 3
z#y
#h.
1
lack of junxun
分别从三个起点开始用bfs进行模拟…看一下代码就懂了
#include
using namespace std;
const int maxn=1e5+5;
int n,m;
char w[1005][1005];
int vis[3][1005][1005];
int dir[8][2]={0,1,0,-1,1,0,-1,0,1,1,-1,-1,1,-1,-1,1};
struct node{
int x,y;
};
bool ju(int x,int y,int id){//判断是否可走
if(x>=1&&x<=n&&y>=1&&y<=m&&w[x][y]!='#'&&vis[id][x][y]==0)
return true;
return false;
}
queue<node> pq[3];
bool bfs(int x){
int num=pq[x].size();
node now,ne;
while(num--){
now=pq[x].front(),pq[x].pop();
for(int i=0;i<8;++i){
if(i>=4&&(x==0||x==1))//z和y不能走斜线,break出去
break;
ne.x=now.x+dir[i][0];
ne.y=now.y+dir[i][1];
if(ju(ne.x,ne.y,x)){
vis[x][ne.x][ne.y]=1;
pq[x].push(ne);
if(vis[0][ne.x][ne.y]&&vis[1][ne.x][ne.y]&&vis[2][ne.x][ne.y]){//如果某一个点3个人都走过,说明可以会合
return true;
}
}
}
}
return false;
}
int solve(){
int step=0;//步数
while(!pq[0].empty()||!pq[1].empty()||!pq[2].empty()){
++step;
if(bfs(0))return step;
if(bfs(1))return step;
for(int i=1;i<=3;++i)
if(bfs(2))return step;
}
return -1;
}
int main()
{
while(~scanf("%d %d",&n,&m)){
memset(vis,0,sizeof(vis));
while(!pq[0].empty())pq[0].pop();
while(!pq[1].empty())pq[1].pop();
while(!pq[2].empty())pq[2].pop();
node now;
for(int i=1;i<=n;++i)
scanf("%s",w[i]+1);
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
if(w[i][j]=='z'){
now.x=i,now.y=j;
vis[0][now.x][now.y]=1;
pq[0].push(now);
}else if(w[i][j]=='y'){
now.x=i,now.y=j;
vis[1][now.x][now.y]=1;
pq[1].push(now);
}else if(w[i][j]=='h'){
now.x=i,now.y=j;
vis[2][now.x][now.y]=1;
pq[2].push(now);
}
}
}
int ans=solve();
if(ans==-1){
printf("lack of junxun\n");
}else{
printf("%d\n",ans);
}
}
}
津津上初中了。妈妈认为津津应该更加用功学习,所以津津除了上学之外,还要参加妈妈为她报名的各科复习班。另外每周妈妈还会送她去学习朗诵、舞蹈和钢琴。但是津津如果一天上课超过八个小时就会不高兴,而且上得越久就会越不高兴。假设津津不会因为其它事不高兴,并且她的不高兴不会持续到第二天。请你帮忙检查一下津津下周的日程安排,看看下周她会不会不高兴;如果会的话,哪天最不高兴。
输入包括七行数据,分别表示周一到周日的日程安排。每行包括两个小于10的非负整数,分别表示津津在学校上课的时间和妈妈安排她上课的时间。
输出包括一行,这一行只包含一个数字。如果不会不高兴那么输出0,如果会那么输出最不高兴的是周几〔用1,2,3,4,5,6,7分别表示周一,周二,周三,周四,周五,周六,周日〕。如果有两天或两天以上不高兴的程度相当,那么输出时间最靠前的一天。
53
62
72
53
54
04
06
3
#include
using namespace std;
const int maxn=1e3+5;
int main()
{
int x,ans=0,ma=0;
for(int i=1;i<=7;++i){
scanf("%d",&x);
if(x%10+x/10>8){
if(ans==0||x%10+x/10>ma){
ans=i;
ma=x%10+x/10;
}
}
}
printf("%d\n",ans);
return 0;
}
鲁宾逊先生有一只宠物猴,名叫多多。这天,他们两个正沿着乡间小路散步,突然发现路边的告示牌上贴着一张小小的纸条:“欢迎免费品尝我种的花生!——熊字”。
鲁宾逊先生和多多都很开心,因为花生正是他们的最爱。在告示牌背后,路边真的有一块花生田,花生植株整齐地排列成矩形网格〔如图1〕。有经验的多多一眼就能看出,每棵花生植株下的花生有多少。为了训练多多的算术,鲁宾逊先生说:“你先找出花生最多的植株,去采摘它的花生;然后再找出剩下的植株里花生最多的,去采摘它的花生;依此类推,不过你一定要在我限定的时间内回到路边。”
我们假定多多在每个单位时间内,可以做以下四件事情中的一件:
1)从路边跳到最靠近路边〔即第一行〕的某棵花生植株;
2)从一棵植株跳到前后左右与之相邻的另一棵植株;
3)采摘一棵植株下的花生;
4)从最靠近路边〔即第一行〕的某棵花生植株跳回路边。
现在给定一块花生田的大小和花生的分布,请问在限定时间内,多多最多可以采到多少个花生?注意可能只有部分植株下面长有花生,假设这些植株下的花生个数各不相同。
例如在样例所示的花生田里,只有位于(2,5),(3,7),(4,2),(5,4)的植株下长有花生,个数分别为13,7,15,9。多多在21个单位时间内,最多可以采到37个花生。
输入的第一行包括三个整数,M,N和K,用空格隔开;表示花生田的大小为M*N〔1<=M,N<=20〕,多多采花生的限定时间为K〔0<=K<=1000〕个单位时间。接下来的M行,每行包括N个非负整数,也用空格隔开;第i+1行的第j个整数Pij〔0<=Pij<=500〕表示花生田里植株(i,j)下花生的数目,0表示该植株下没有花生。
输出包括一行,这一行只包含一个整数,即在限定时间内,多多最多可以采到花生的个数。
6 7 21
0 0 0 0 0 0 0
0 0 0 0 13 0 0
0 0 0 0 0 0 7
0 15 0 0 0 0 0
0 0 0 9 0 0 0
0 0 0 0 0 0 0
37
将每一个株花生的坐标和花生数量用结构体储存,按花生数量降序排序。//题目要求按花生数量采摘
要考虑返回的时间,采摘一个花生的条件是采摘完它后还有时间返回路边
#include
#include
#include
#include
using namespace std;
int pic[50][50];
int ans,n,m,k,cnt,nowx,nowy,tot;
struct edge{
int x,y,v;
}e[5000];
bool cmp(edge a,edge b){
return a.v > b.v;
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i = 1; i<=n; i++){
for(int j = 1; j<=m; j++){
scanf("%d",&pic[i][j]);
if(pic[i][j]){
cnt ++;
e[cnt].x = i;e[cnt].y =j;e[cnt].v = pic[i][j];
}
}
}
sort(e+1,e+1+cnt,cmp);
if(2*e[1].y + 1 > k){
printf("0\n");
return 0;
}
nowy = e[1].y;
for(int i = 1; i<=cnt; i++){
tot += abs(nowy - e[i].y) + abs(nowx - e[i].x) + 1;
if(tot + e[i].x > k)break;
nowx = e[i].x;
nowy = e[i].y;
ans += e[i].v;
}
printf("%d\n",ans);
return 0;
}
我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全“1”串称为I串,既含“0”又含“1”的串那么称为F串。
FBI树是一种二叉树[1],它的结点类型也包括F结点,B结点和I结点三种。由一个长度为2N的“01”串S可以构造出一棵FBI树T,递归的构造方法如下:
1)T的根结点为R,其类型与串S的类型相同;
2)假设串S的长度大于1,将串S从中间分开,分为等长的左右子串S1和S2;由左子串S1构造R的左子树T1,由右子串S2构造R的右子树T2。
现在给定一个长度为2N的“01”串,请用上述构造方法构造出一棵FBI树,并输出它的后序遍历序列[2]。
第一行是一个整数N〔1<=N<=128〕,数据保证n为2的幂次方。
第二行是一个长度为2N的“01”串。
输出包括一行,这一行只包含一个字符串,即FBI树的后序遍历序列。
4
10001011
IBFBBBFIBFIIIFF
[1]二叉树:二叉树是结点的有限集合,这个集合或为空集,或由一个根结点和两棵不相交的二叉树组成。这两棵不相交的二叉树分别称为这个根结点的左子树和右子树。
[2]后序遍历:后序遍历是深度优先遍历二叉树的一种方法,它的递归定义是:先后序遍历左子树,再后序遍历右子树,最后访问根。
递归建树,自底向上求出节点的类型
再后序遍历输出
#include
using namespace std;
const int maxn=1e5+5;
struct node{
int l,r;
char v;
}tr[maxn];
char s[maxn];
void build(int e,int l,int r){
tr[e].l=l,tr[e].r=r;
if(l==r){
tr[e].v=s[l]=='0'?'B':'I';
return;
}
int mid=(l+r)>>1;
build(e<<1,l,mid);
build(e<<1|1,mid+1,r);
if(tr[e<<1].v=='B'&&tr[e<<1|1].v=='B'){
tr[e].v='B';
}else if(tr[e<<1].v=='I'&&tr[e<<1|1].v=='I'){
tr[e].v='I';
}else{
tr[e].v='F';
}
}
void cout_(int e,int l,int r){
if(l==r){
printf("%c",tr[e].v);
return;
}
int mid=(l+r)>>1;
cout_(e<<1,l,mid);
cout_(e<<1|1,mid+1,r);
printf("%c",tr[e].v);
}
int main()
{
int n;
while(~scanf("%d %s",&n,s+1)){
int ls=strlen(s+1);
build(1,1,ls);
cout_(1,1,ls);
printf("\n");
}
return 0;
}
人类终于登上了火星的土地并且见到了神秘的火星人。人类和火星人都无法理解对方的语言,但是我们的科学家发明了一种用数字交流的方法。这种交流方法是这样的,首先,火星人把一个非常大的数字告诉人类科学家,科学家破解这个数字的含义后,再把一个很小的数字加到这个大数上面,把结果告诉火星人,作为人类的回答。
火星人用一种非常简单的方式来表示数字——掰手指。火星人只有一只手,但这只手上有成千上万的手指,这些手指排成一列,分别编号为1,2,3……。火星人的任意两根手指都能随意交换位置,他们就是通过这方法计数的。
一个火星人用一个人类的手演示了如何用手指计数。如果把五根手指——拇指、食指、中指、无名指和小指分别编号为1,2,3,4和5,当它们按正常顺序排列时,形成了5位数12345,当你交换无名指和小指的位置时,会形成5位数12354,当你把五个手指的顺序完全颠倒时,会形成54321,在所有能够形成的120个5位数中,12345最小,它表示1;12354第二小,它表示2;54321最大,它表示120。下表展示了只有3根手指时能够形成的6个3位数和它们代表的数字:
三进制数
123
132
213
231
312
321
代表的数字
1
2
3
4
5
6
现在你有幸成为了第一个和火星人交流的地球人。一个火星人会让你看他的手指,科学家会告诉你要加上去的很小的数。你的任务是,把火星人用手指表示的数与科学家告诉你的数相加,并根据相加的结果改变火星人手指的排列顺序。输入数据保证这个结果不会超出火星人手指能表示的范围。
输入包括三行,第一行有一个正整数N,表示火星人手指的数目〔1<=N<=10000〕。第二行是一个正整数M,表示要加上去的小整数〔1<=M<=100〕。下一行是1到N这N个整数的一个排列,用空格隔开,表示火星人手指的排列顺序。
输出只有一行,这一行含有N个整数,表示改变后的火星人手指的排列顺序。每两个相邻的数中间用一个空格分开,不能有多余的空格。
5
3
1 2 3 4 5
1 2 4 5 3
其实就是将输入的排列变成字典序在它后面第m个的排列
可以用next_permutation函数(将一个排列变成字典序在它后一个的排列)
#include
using namespace std;
const int maxn=1e4+5;
int a[maxn];
int main()
{
int n,m;
while(~scanf("%d",&n)){
scanf("%d",&m);
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
}
while(m--){
next_permutation(a+1,a+n+1);
}
for(int i=1;i<=n;++i){
printf("%d%c",a[i],i==n?'\n':' ');
}
}
return 0;
}
小B在一个有N个城市M条道路的国家,每条道路连接的城市可以互相到达且每条道路小B都要花1步去走过它。现在他在1号城市,问他走P步最多能走多少个不同的城市?
输入格式:第1行,三个正整数N、M、P,意义如题:接下来M行,每行两个整数U、V,表示存在一条连接U、V的无向边。
输出格式:1行,一个整数,表示从1号城市出发走P步的所有情况,共能经过多少个不同的城市。
4 4 2
1 2
1 3
2 3
3 4
4
数据规模:
1<=N<=100000,1<=M<=5000000,1<=P<=10000
bfs或者dfs
但是不能直接开那么大的数组,要用链式前向星或者vector
从1开始bfs,将遍历过的点标记
#include
using namespace std;
const int maxn=1e7+5;
int n,m,p;
struct node{
int x,step;
};
vector<int> w[100005];
int vis[100005],ans;
void bfs(){
queue<node> pq;
node now,ne;
now.x=1,now.step=0;
vis[1]=1;
pq.push(now);
while(!pq.empty()){
now=pq.front(),pq.pop();
for(int i=0;i<w[now.x].size();++i){
ne.x=w[now.x][i],ne.step=now.step+1;
if(vis[ne.x]==0&&ne.step>=0){
++ans;
vis[ne.x]=1;
pq.push(ne);
}
}
}
}
int main()
{
while(~scanf("%d %d %d",&n,&m,&p)){
memset(vis,0,sizeof(vis));
ans=1;
for(int i=1;i<=m;++i){
int a,b;
scanf("%d %d",&a,&b);
w[a].push_back(b);
w[b].push_back(a);
}
bfs();
printf("%d\n",ans);
}
return 0;
}
从1开始dfs,将遍历过的点标记
答案就是被标记的城市数
不过要注意一个特殊情况
所以标记的时候标记数组存的是步数…如代码中进行是否继续dfs的判断
dfs的前向星写法
#include
using namespace std;
const int maxn=1e7+5;
int n,m,p;
struct node{
int to,next;
}edge[maxn];
int head[100005],vis[100005],cnt,ans;
void dfs(int now,int num){
if(vis[now]==0){
++ans;
}
vis[now]=num;
if(num>p){
return;
}
for(int i=head[now];i!=-1;i=edge[i].next){
int to=edge[i].to;
if(vis[to]==0||num+1<vis[to]){
dfs(to,num+1);
}
}
}
void add(int a,int b){
edge[++cnt].to=b;
edge[cnt].next=head[a];
head[a]=cnt;
}
int main()
{
while(~scanf("%d %d %d",&n,&m,&p)){
memset(vis,0,sizeof(vis));
memset(head,-1,sizeof(head));
cnt=ans=0;
for(int i=1;i<=m;++i){
int a,b;
scanf("%d %d",&a,&b);
add(a,b),add(b,a);
}
dfs(1,1);
printf("%d\n",ans);
}
return 0;
}
dsf的vector写法
#include
using namespace std;
const int maxn=1e7+5;
int n,m,p;
vector<int> w[100005];
int vis[100005],ans;
void dfs(int now,int num){
if(vis[now]==0){
++ans;
}
vis[now]=num;
if(num>p){
return;
}
for(int i=0;i<w[now].size();++i){
int to=w[now][i];
if(vis[to]==0||num+1<vis[to]){
dfs(to,num+1);
}
}
}
int main()
{
while(~scanf("%d %d %d",&n,&m,&p)){
memset(vis,0,sizeof(vis));
ans=0;
for(int i=1;i<=m;++i){
int a,b;
scanf("%d %d",&a,&b);
w[a].push_back(b);
w[b].push_back(a);
}
dfs(1,1);
printf("%d\n",ans);
}
return 0;
}
括号主要有:大括号“{ }”、中括号“[ ]”、小括号“( )”。给定一个只包含左右括号的合法括号序列(序列长度2<=n<=10000),按右括号从左到右的顺序输出每一对配对的括号出现的位置(括号序列以0开始编号)
输入格式:仅1行,表一个合法的括号序列
输出格式:设括号序列有n个右括号,每行两个整数l、r,表示配对的括号左括号出现在第l位,右括号出现在第r位。
{()[()()]}()
1 2
4 5
6 7
3 8
0 9
10 11
用栈处理
从左到右遍历字符,如果和栈顶匹配,则出栈并输出对应的下标对,否则入栈
#include
using namespace std;
const int maxn=1e5+5;
char s[maxn];
struct node{
int id;
char v;
};
int main()
{
while(~scanf("%s",s)){
stack<node> sta;
int ls=strlen(s);
node now;
for(int i=0;i<ls;++i){
now.id=i;
if(s[i]=='(')now.v=')';
if(s[i]=='{')now.v='}';
if(s[i]=='[')now.v=']';
if(!sta.empty()&&sta.top().v==s[i]){
printf("%d %d\n",sta.top().id,i);
sta.pop();
}else{
sta.push(now);
}
}
}
return 0;
}
有n个小朋友,按顺时针方向围成一圈(编号从1—n),从第1号开始报数,一直数到m,数到m的小朋友退出圈外,剩下的小朋友再接着从1开始报数。
T组数据,第一行为T(1<=T<=10)
接下来T行,每行用空格分开两个整数n、m(1<=m,n<=10000)
输出T行
每行一个答案表示第1号小朋友退出前,报数为m的次数
1
6 2
4
典型的约瑟夫环问题
数组暴力模拟需要移动的数太多,用数组标记进行计数也太耗时
链表模拟(这里是用数组模拟链表)
#include
using namespace std;
const int maxn=1e5+5;
int next_[10005],pre[10005];
int main()
{
int n,m,t;
scanf("%d",&t);
while(t--){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;++i){
next_[i]=i+1;
pre[i]=i-1;
}
next_[n]=1,pre[1]=n;
int ans=0,now=1;
while(1){
int x=m-1;
while(x--){
now=next_[now];
}
//cout<
if(now==1)break;
next_[pre[now]]=next_[now];
pre[next_[now]]=pre[now];
now=next_[now];
++ans;
}
printf("%d\n",ans);
}
}
约瑟夫环问题递归解法解释1
约瑟夫环问题递归解法解释2
#include
using namespace std;
const int maxn=1e5+5;
int dfs( int n, int m, int k)
{
if(k==1)
return(n+m-1) %n;
else
return(dfs(n-1,m,k-1)+m) %n;
}
int main()
{
int n,m,t;
scanf("%d",&t);
while(t--){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;++i){
if(dfs(n,m,i)==0){
printf("%d\n",i-1);
break;
}
}
}
}
小A生活在一个神奇的国家,这个国家有N(N<=100000)个城市,还有M(M<=5000000)条道路连接两城市。道路连接的两个城市可以直接免费到达。小A比较烦恼,因为他想知道每个城市能直接到达哪些城市,你能帮帮他吗?保证每个城市都有道路与其连接。(注:按照输入的道路顺序输出每个城市直接连接的城市,若有城市出现多次,则按最小出现次序输出)
第1行包含两个整数N和M;接下来M行,每行两个整数描述一条道路连接的两个城市的编号。
输出N行,每行若干个用一个空格隔开的整数;第I行输出的是与城市I直接相连城市编号,保证城市的出现按照道路输入的先后顺序出现。
4 5
2 3
3 1
1 4
2 4
1 2
3 4 2
3 4 1
2 1
1 2
用vector储存边的情况
因为可能有重边,需要用set或者map判断。而且还是多组输入
map
#include
using namespace std;
const int maxn=1e5+5;
vector<int> w[maxn];
map<int,int> mp[maxn];
int main()
{
int n,m;
while(~scanf("%d %d",&n,&m)){
for(int i=1;i<=m;++i){
int a,b;
scanf("%d %d",&a,&b);
//if(a==b)
// continue;
if(mp[a][b]==0)
w[a].push_back(b),mp[a][b]=1;
if(mp[b][a]==0)
w[b].push_back(a),mp[b][a]=1;
}
for(int i=1;i<=n;++i){
int l=w[i].size();
if(l!=0)
for(int j=0;j<l;++j){
printf("%d%c",w[i][j],j==l-1?'\n':' ');
}
}
for(int i=1;i<=n;++i){
w[i].clear();
mp[i].clear();
}
}
}
set
#include
using namespace std;
const int maxn=1e5+5;
vector<int> w[maxn];
set<int> se[maxn];
int main()
{
int n,m;
while(~scanf("%d %d",&n,&m)){
for(int i=1;i<=m;++i){
int a,b;
scanf("%d %d",&a,&b);
//if(a==b)
// continue;
if(se[a].find(b)==se[a].end())
w[a].push_back(b),se[a].insert(b);
if(se[b].find(a)==se[b].end())
w[b].push_back(a),se[b].insert(a);
}
for(int i=1;i<=n;++i){
int l=w[i].size();
if(l!=0)
for(int j=0;j<l;++j){
printf("%d%c",w[i][j],j==l-1?'\n':' ');
}
}
for(int i=1;i<=n;++i){
w[i].clear();
se[i].clear();
}
}
}
小B在一个有N个城市M条道路的国家,每条道路连接的城市可以互相到达且每条道路都要花1步去走过它。现在他在P号城市,问有多少城市走1步能到达该城市?
多组输入
第1行,三个正整数N、M、P,意义如题。
接下来M行,每行两个整数U、V,表示存在一条连接U、V的无向边。(0<=N<=1000000,0<=M<=500000)
1行,走1步能到P城市的城市数量。
4 4 1
1 2
1 3
2 3
3 4
2
map判断
不过可能有自环,自环也算一种情况
#include
using namespace std;
const int maxn=1e5+5;
map<int,int> mp;
int main()
{
int n,m,p;
while(~scanf("%d %d %d",&n,&m,&p)){
mp.clear();
int ans=0;
while(m--){
int a,b;
scanf("%d %d",&a,&b);
if(a==p&&mp[b]==0){
++ans;
mp[b]=1;
}
if(b==p&&mp[a]==0){
++ans;
mp[a]=1;
}
}
printf("%d\n",ans);
}
}