Rainbow擅长玩战棋类游戏。著名的战棋游戏有很多,例如《曹操传》、《瓦岗山异闻录》等。在本题中,我们考虑战棋游戏的一个简单版本,基于以下规则:
地图
地图是一个N行M列的矩阵,矩阵中的不同位置有不同的地形,例如平原、树林、山地、河流、雪原等。在这里,我们给矩阵中的每个位置规定一个正整数,这个整数会对在矩阵中的移动产生影响。
角色
每个角色均可被视作位于矩阵中某个位置上的人物。每个角色具有生命值HP, 攻击力AT, 移动力MV和攻击范围[AD1 AD2]。角色被分为两个阵营,第0阵营被玩家控制,第1阵营被系统控制。
当两个不同阵营的角色p和q的曼哈顿距离处于p的攻击范围内(包含端点)时,p可以攻击q。若q被p攻击,则q的生命值被减去p的攻击力。当一个角色的生命值<=0时,它将立即被移除出地图,离开游戏。
每个角色均占领地图上的一个位置,并且可以在地图上移动,遵循以下规则:
占领
最初,每个角色在地图的不同位置生成。他们各自占领自己所在的位置。当一个角色在移动时,其它角色均不能移动。
一个角色开始移动前失去对所在位置的占领权,停止移动时获得所在位置的占领权。
“移动”与“步”
一次移动由若干步组成。在每一步中,一个角色可以从当前位置走向四个方向上相邻的位置,但不能走到被其它角色占领的位置上。
当一个角色从i,j 走到x,y 时, 它的移动力会被扣除Gx,y。使得移动力变为负数的“步”是不合法的。在合法的一“步”完成后,若该角色正处于与对方阵营某个角色相邻(四个方向)的位置上,则该角色的移动力立即被减为0,换句话说,他将不能再走另外一步。
当一次“移动”结束后,角色的移动力恢复为初始值。
能被一个角色通过若干合法“步”到达的位置集合称为该角色的移动范围。停留在原地也是合法的,故也被算入移动范围。
游戏的过程由若干轮组成,每轮玩家阵营先行动,系统阵营后行动。对于每个阵营,该阵营的所有角色轮流行动。在每次行动中,一个角色先移动到移动范围内的任意一个位置,然后可能会攻击对方阵营的一个角色(或什么也不做)。 当一个阵营的所有角色均被移除出地图时,另外一个阵营获胜。
Rainbow得到了一份游戏日志,请帮他复原这个游戏的过程。
地图
地图是一个N行M列的矩阵,矩阵中的不同位置有不同的地形,例如平原、树林、山地、河流、雪原等。在这里,我们给矩阵中的每个位置规定一个正整数,这个整数会对在矩阵中的移动产生影响。
角色
每个角色均可被视作位于矩阵中某个位置上的人物。每个角色具有生命值HP, 攻击力AT, 移动力MV和攻击范围[AD1 AD2]。角色被分为两个阵营,第0阵营被玩家控制,第1阵营被系统控制。
当两个不同阵营的角色p和q的曼哈顿距离处于p的攻击范围内(包含端点)时,p可以攻击q。若q被p攻击,则q的生命值被减去p的攻击力。当一个角色的生命值<=0时,它将立即被移除出地图,离开游戏。
每个角色均占领地图上的一个位置,并且可以在地图上移动,遵循以下规则:
占领
最初,每个角色在地图的不同位置生成。他们各自占领自己所在的位置。当一个角色在移动时,其它角色均不能移动。
一个角色开始移动前失去对所在位置的占领权,停止移动时获得所在位置的占领权。
“移动”与“步”
一次移动由若干步组成。在每一步中,一个角色可以从当前位置走向四个方向上相邻的位置,但不能走到被其它角色占领的位置上。
当一个角色从i,j 走到x,y 时, 它的移动力会被扣除Gx,y。使得移动力变为负数的“步”是不合法的。在合法的一“步”完成后,若该角色正处于与对方阵营某个角色相邻(四个方向)的位置上,则该角色的移动力立即被减为0,换句话说,他将不能再走另外一步。
当一次“移动”结束后,角色的移动力恢复为初始值。
能被一个角色通过若干合法“步”到达的位置集合称为该角色的移动范围。停留在原地也是合法的,故也被算入移动范围。
游戏的过程由若干轮组成,每轮玩家阵营先行动,系统阵营后行动。对于每个阵营,该阵营的所有角色轮流行动。在每次行动中,一个角色先移动到移动范围内的任意一个位置,然后可能会攻击对方阵营的一个角色(或什么也不做)。 当一个阵营的所有角色均被移除出地图时,另外一个阵营获胜。
Rainbow得到了一份游戏日志,请帮他复原这个游戏的过程。
Input
第一行 4 个整数 N,M,C,E(1≤N,M≤100,2≤C≤min(N×M,100),1≤E≤3000) 表示地图行数、列数、角色数、日志事件数。 接下来N行每行M个整数Gi,j(1≤Gi,j≤10^2) 。
接下来 C 行每行 8 个整数 HP,AT,MV,AD 1 ,AD 2 ,ST x ,ST y ,GR(1≤HP,AT,MV≤10^3, 1≤AD1≤AD2≤20,1≤STx≤N,1≤STy≤M,0≤GR≤1) , 表示角色的 5 个属性以及初始位置、所属阵营。
接下来 E 行描述日志中的事件,每个事件都是以下格式之一:
Round of GR – 阵营 GR 行动回合开始。
Action of character ID – 角色ID 行动开始。
Move to (x,y) – 当前行动角色通过若干步移动到 (x,y) 。
Attack ID – 当前行动角色攻击角色ID 但是角色 ID在攻击后未被移除。
Drive out ID – 当前行动角色攻击角色ID并造成ID 被移出游戏。
在事件中,1≤x≤N,1≤y≤M,1≤ID≤C,0≤GR≤1 。 行列标号从1开始,每个阵营初始至少拥有1个角色。
接下来 C 行每行 8 个整数 HP,AT,MV,AD 1 ,AD 2 ,ST x ,ST y ,GR(1≤HP,AT,MV≤10^3, 1≤AD1≤AD2≤20,1≤STx≤N,1≤STy≤M,0≤GR≤1) , 表示角色的 5 个属性以及初始位置、所属阵营。
接下来 E 行描述日志中的事件,每个事件都是以下格式之一:
Round of GR – 阵营 GR 行动回合开始。
Action of character ID – 角色ID 行动开始。
Move to (x,y) – 当前行动角色通过若干步移动到 (x,y) 。
Attack ID – 当前行动角色攻击角色ID 但是角色 ID在攻击后未被移除。
Drive out ID – 当前行动角色攻击角色ID并造成ID 被移出游戏。
在事件中,1≤x≤N,1≤y≤M,1≤ID≤C,0≤GR≤1 。 行列标号从1开始,每个阵营初始至少拥有1个角色。
Output
对于每个Move to事件, 若无法到达,输出“INVALID”,否则输出当它进入终点,准备结束“移动”前最多剩余多少移动力(移动力变化的优先顺序为:减去G→ G→ 若与对方阵营相邻扣为 0→ 0→ 输出→ → 恢复初始值)。
对于每个Attack or Drive out事件,若不能攻击或者攻击造成的是否移出地图的情况与输入不相符,输出“INVALID”,否则输出攻击后被攻击角色剩余 HP HP 。
不合法的事件在处理后续事件时应当被忽略。数据保证输入完成时游戏恰好结束,并且Round of and Action of类事件被正确记录,没有缺失或者矛盾。
对于每个Attack or Drive out事件,若不能攻击或者攻击造成的是否移出地图的情况与输入不相符,输出“INVALID”,否则输出攻击后被攻击角色剩余 HP HP 。
不合法的事件在处理后续事件时应当被忽略。数据保证输入完成时游戏恰好结束,并且Round of and Action of类事件被正确记录,没有缺失或者矛盾。
样例输入1 |
样例输出1 |
5 5 4 12 1 9 1 4 4 1 9 1 2 4 1 9 1 1 2 2 9 2 7 3 2 3 2 6 1 10 5 8 1 3 1 1 0 20 10 5 1 2 2 1 0 19 10 5 1 2 5 2 1 25 25 3 1 1 5 5 0 Round of 0 Action of character 2 Move to (5,1) Attack 3 Action of character 1 Move to (3,1) Round of 1 Action of character 3 Drive out 1 Round of 0 Action of character 2 Drive out 3 |
0 9 6 INVALID -1 |
Hint
【数据规模与约定】
对于80%的数据,不存在不合法事件。
对于100%的数据,参见输入输出格式中给定的范围与保证。
对于80%的数据,不存在不合法事件。
对于100%的数据,参见输入输出格式中给定的范围与保证。
【分析】
本题考察基本功,并没有太多的算法上的要求。
只需要认真阅读题意,谨慎地按照题目所要求的编写代码。
有几个需要注意的地方:
1·不能攻击队友。
2·可以走到原地。
3·移动中碰到队友是不会把移动力变成0的。
4·注意死亡的人要移除游戏,死亡后再操作是非法的。
5·本题的输入有点奇怪。有时会多几个空格。
code:
不存在的,我写不出来的
我的30分代码。。。。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #define N 200 6 using namespace std; 7 long long dx[4]={0,0,1,-1}; 8 long long dy[4]={1,-1,0,0}; 9 long long group[N],stx[N],sty[N],n,m,C,E,survive[N]; 10 long long check_group(long long x,long long y,long long GROUP){//检查当前步是不是走到了对方的旁边 11 for(long long i=1;i<=C;i++){ 12 if(group[i]==GROUP)continue;//自己的人不需要有这些限定 13 if(survive[i]==0)continue;//死了 14 if(stx[i]==x&&sty[i]==y+1)return 1;//下面是检查相邻的部分 15 if(stx[i]==x&&sty[i]==y-1)return 1; 16 if(stx[i]==x+1&&sty[i]==y)return 1; 17 if(stx[i]==x-1&&sty[i]==y)return 1; 18 } 19 return 0; 20 } 21 long long max0=0,G[N][N],dis[N][N]; 22 void check_move(long long now_x,long long now_y,long long final_x,long long final_y,long long rest_MV,long long GROUP){ 23 if(dis[now_x][now_y]!=-1&&dis[now_x][now_y]>=rest_MV)return; 24 // cout<<"nowx->"<<now_x<<" nowy->"<<now_y<<" finalx->"<<final_x<<" finaly->"<<final_y<<" ->rest"<<rest_MV<<' '; 25 if(now_x==final_x&&now_y==final_y){ 26 if(dis[now_x][now_y]!=-1&&dis[now_x][now_y]>=rest_MV)return; 27 dis[now_x][now_y]=rest_MV; 28 max0=max(max0,rest_MV);//更新最大值 29 return; 30 } 31 dis[now_x][now_y]=rest_MV; 32 if(rest_MV<=max0)return; 33 if(rest_MV<=0)return ;//如果没能到达终点并且没有步数可以走了就直接不行 34 for(long long i=0;i<4;i++){ 35 long long tx=now_x+dx[i],ty=now_y+dy[i]; 36 if(check_group(tx,ty,GROUP)){//如果下一步是对方的旁边就直接削减成0 37 if(rest_MV-G[tx][ty]<0)continue; 38 check_move(tx,ty,final_x,final_y,0,GROUP); 39 continue; 40 } 41 if(tx>n||tx<1||ty<1||ty>m)continue; 42 check_move(tx,ty,final_x,final_y,rest_MV-G[tx][ty],GROUP); 43 } 44 } 45 long long ad1[N],ad2[N],hp[N],at[N],mv[N],nowpeople,nowx,nowy,nowgroup; 46 int main() { 47 ios::sync_with_stdio(false); 48 cin>>n>>m>>C>>E; 49 for(long long i=1; i<=n; i++) 50 for(long long j=1; j<=m; j++) 51 cin>>G[i][j]; 52 for(long long i=1; i<=C; i++) { 53 cin>>hp[i]>>at[i]>>mv[i]>>ad1[i]>>ad2[i]>>stx[i]>>sty[i]>>group[i]; 54 survive[i]=1;//这个人还活着,初始化 55 } 56 string k; 57 while(E--) { 58 cin>>k; 59 string zyh; 60 if(k=="Attack") { //打人但是没有打死的情况 61 long long ID; 62 cin>>ID; 63 if(survive[ID]==0) { 64 cout<<"INVALID"<<' ';//如果这个人已经死亡了,那么显然是不合法的 65 continue; 66 } 67 if(group[ID]==group[nowpeople]) { //如果是自己人当然就不合法 68 cout<<"INVALID"<<' '; 69 continue; 70 } 71 long long distance=abs(stx[ID]-nowx)+abs(sty[ID]-nowy); 72 if(distance>ad2[nowpeople]||distance<ad1[nowpeople]) { //如果打不到这个人就代表是不合法的 73 cout<<"INVALID"<<' '; 74 continue; 75 } 76 if(hp[ID]-at[nowpeople]<=0) { //如果被打死了,在该状态下是不合法的 77 cout<<"INVALID"<<' '; 78 continue; 79 } 80 hp[ID]-=at[nowpeople];//否则就减去这个人的值 81 cout<<hp[ID]<<' '; 82 } else if(k=="Action") { //代表现在行动的人 ,因为题目描述没有矛盾,所以不做太多判断 83 cin>>zyh; 84 cin>>zyh; 85 long long ID; 86 cin>>ID; 87 nowpeople=ID; 88 nowx=stx[ID]; 89 nowy=sty[ID]; 90 } else if(k=="Round") { //代表该轮中行动的团队 ,题目描述没有矛盾,所以不做判断 91 cin>>zyh; 92 long long GR; 93 cin>>GR; 94 nowgroup=GR; 95 } else if(k=="Move") { 96 long long X=0,Y=0; 97 cin>>zyh; 98 cin>>k; 99 long long flag=0; 100 for(long long i=0; i<k.size(); i++) { 101 if(!isdigit(k[i])&&!flag)continue; 102 if(isdigit(k[i])&&(flag==1||flag==0)) { 103 flag=1; 104 X=(X<<3)+(X<<1)+k[i]-'0'; 105 continue; 106 } 107 if(flag==1&&!isdigit(k[i])) { 108 flag=2; 109 continue; 110 } 111 if(isdigit(k[i])&&flag==2) { 112 Y=(Y<<3)+(Y<<1)+k[i]-'0'; 113 continue; 114 } 115 } 116 //cout<<X<<" "<<Y<<endl;///////////// 117 for(long long i=1; i<=C; i++) { 118 if(X==stx[i]&&Y==sty[i]&&group[i]!=group[nowpeople]&&survive[i]) { //如果走到了对方的地方显然是不合法的 119 cout<<"INVALID"<<' '; 120 } 121 } 122 max0=-1; 123 memset(dis,-1,sizeof dis); 124 check_move(nowx,nowy,X,Y,mv[nowpeople],group[nowpeople]); 125 if(dis[X][Y]==-1){ 126 cout<<"INVALID"<<' '; 127 continue; 128 } 129 cout<<dis[X][Y]<<' '; 130 nowx=X,nowy=Y; 131 stx[nowpeople]=X,sty[nowpeople]=Y; 132 } else if(k=="Drive") { 133 cin>>zyh; 134 long long ID; 135 cin>>ID; 136 if(survive[ID]==0) {//这个人已经死亡了,显然是不合法的状态 137 cout<<"INVALID"<<' '; 138 continue; 139 } 140 if(group[ID]==group[nowpeople]) { //如果是自己人当然就不合法 141 cout<<"INVALID"<<' '; 142 continue; 143 } 144 long long distance=abs(stx[ID]-nowx)+abs(sty[ID]-nowy); 145 if(distance>ad2[nowpeople]||distance<ad1[nowpeople]) { //如果打不到这个人就代表是不合法的 146 cout<<"INVALID"<<' '; 147 continue; 148 } 149 if(hp[ID]-at[nowpeople]>0) { //如果没有被打死,在该状态下是不合法的 150 cout<<"INVALID"<<' '; 151 continue; 152 } 153 hp[ID]-=at[nowpeople];//否则就减去这个人的值 154 survive[ID]=0;//打标记代表这个人已经死亡了 155 stx[ID]=-9999;//坐标肯定要作废 156 sty[ID]=-9999; 157 cout<<hp[ID]<<' '; 158 } 159 } 160 return 0; 161 }
正解AC的代码:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 using namespace std; 6 int n,m,C,E,Rnd,id,G[105][105]; 7 int belong[105][105]; 8 int dis[105][105]; 9 struct Character{ 10 int HP,AT,MV,AD1,AD2; 11 int x,y,GR; 12 bool DIE; 13 }p[105]; 14 int getint(){ 15 char c=getchar();int sum=0; 16 while(!isdigit(c))c=getchar(); 17 while(isdigit(c)){sum=sum*10+c-48;c=getchar();} 18 return sum; 19 } 20 int fx[]={1,-1,0,0}; 21 int fy[]={0,0,1,-1}; 22 void dfs(int x,int y,int mv,bool flag){ 23 if(mv<0)return; 24 if(flag){ 25 if(belong[x-1][y]&&belong[x-1][y]!=Rnd+1)mv=0; 26 if(belong[x+1][y]&&belong[x+1][y]!=Rnd+1)mv=0; 27 if(belong[x][y-1]&&belong[x][y-1]!=Rnd+1)mv=0; 28 if(belong[x][y+1]&&belong[x][y+1]!=Rnd+1)mv=0; 29 } 30 if(dis[x][y]>=mv)return; 31 dis[x][y]=max(dis[x][y],mv); 32 int xx,yy; 33 for(int i=0;i<4;++i){ 34 xx=x+fx[i];yy=y+fy[i]; 35 if(xx>n||xx<1||yy>m||yy<1)continue; 36 if(belong[xx][yy])continue; 37 dfs(xx,yy,mv-G[xx][yy],true); 38 } 39 } 40 void Move(int k){ 41 int x=getint(),y=getint(); 42 if(x==p[k].x&&y==p[k].y){ 43 cout<<p[k].MV<<" "; 44 return; 45 } 46 if(x>n||x<1||y>m||y<1){ 47 printf("INVALID "); 48 return; 49 } 50 memset(dis,-1,sizeof(dis)); 51 dfs(p[k].x,p[k].y,p[k].MV,false); 52 if(dis[x][y]<0){ 53 printf("INVALID "); 54 return; 55 } 56 belong[p[k].x][p[k].y]=0; 57 belong[x][y]=Rnd+1; 58 p[k].x=x;p[k].y=y; 59 cout<<dis[x][y]<<' '; 60 } 61 void Kill(int x,int y,int type){ 62 if(p[x].GR==p[y].GR||p[x].DIE||p[y].DIE){ 63 printf("INVALID "); 64 return; 65 } 66 int dis=abs(p[y].x-p[x].x)+abs(p[y].y-p[x].y); 67 if(dis>p[x].AD2||dis<p[x].AD1){ 68 printf("INVALID "); 69 return; 70 } 71 int rest=p[y].HP-p[x].AT,tp; 72 if(rest<=0)tp=1;else tp=0; 73 if(tp!=type){ 74 printf("INVALID "); 75 return; 76 } 77 p[y].HP=rest; 78 cout<<rest<<' '; 79 if(tp){ 80 belong[p[y].x][p[y].y]=0; 81 p[y].DIE=true; 82 } 83 } 84 int main(){ 85 scanf("%d%d%d%d",&n,&m,&C,&E); 86 for(int i=1;i<=n;i++) 87 for(int j=1;j<=m;++j) 88 scanf("%d",&G[i][j]); 89 for(int i=1;i<=C;++i){ 90 p[i].HP=getint();p[i].AT=getint();p[i].MV=getint(); 91 p[i].AD1=getint();p[i].AD2=getint(); 92 p[i].x=getint();p[i].y=getint(); 93 p[i].GR=getint(); 94 belong[p[i].x][p[i].y]=p[i].GR+1; 95 } 96 char t1,t2; 97 for(int i=1;i<=E;++i){ 98 t1=getchar(); 99 while(t1!='R'&&t1!='A'&&t1!='M'&&t1!='D')t1=getchar(); 100 switch(t1){ 101 case 'R':Rnd=getint();break; 102 case 'M':Move(id);break; 103 case 'D':Kill(id,getint(),1);break; 104 case 'A':{ 105 t2=getchar(); 106 if(t2=='c')id=getint(); 107 else Kill(id,getint(),0); 108 break; 109 } 110 } 111 } 112 return 0; 113 }
我还会来做的,也许是很久很久之后。。。。
over