P8874 二人的大富翁游戏

题目

前情提要

小模拟,题目看懂就结束了
但我没看懂,orz

警示后人:

  1. 路上经过的每一个点都要判断建筑属于谁并判断得钱还是交钱
  2. 交钱要交到对方手里
  3. 两个人都操作完才算一回合,是否进入下一回合的判断要在if(x==1)里面
  4. 注意 判断升级边界的代码 的位置
  5. 初始资金别忘了(悲)
  6. 一个建筑的价值(题目中的\(a_i\))等于你在这建筑上消耗的总钱数
  7. 输入的时候判断游戏何时结束(尽管题目上说操作1的次数恰好等于2*回合数,但无法判断后面是否跟着一个2操作,所以还是要写!=EOF)

小技巧:给自己写注释是好习惯,尤其是模拟

代码(带注释)
#include<bits/stdc++.h>
using namespace std;
#define int long long		//竟然要开long long 

int n,m,q,l;		        //格子数、初始资金、回合数、建筑物等级上限
int a[111];			//走到第 i 格时,如果是自己的则获得 a[i][j] 元,是对方的则支付 a[i][j] 元 
int c[111][111];	        //第 i 格建筑升到 j+1 级所需价钱 
int d[111];			//每回合第 i 格建筑提供资金 
int b[111];			//第 i 格建筑属于谁(1=莲子/0=梅莉/-1=没有) 
int e[111];			//第 i 格建筑当前等级(初始为 -1)
int x,k;			//行动种类、行动次数(x=1 时切换行动方,行动方走到第 now+k 格;x=2 时当前行动方对第 i 格建筑升 k 级)
bool t;				//当前行动方(1=莲子/0=梅莉) 
int p[2]; 			//当前所在位置(1=莲子/0=梅莉) 
int y[2];			//当前持有的钱数(1=莲子/0=梅莉)
int h[2];			//判断是否进入下一回合(本回合两人都已行动过一次后 x==1 时进入下一回合) 

void __pre()	//初始化 
{
	scanf("%lld%lld%lld%lld",&n,&m,&q,&l);
	for(int i=1;i<=n;++i)
	{
		for(int j=0;j<l;++j)
		{
			scanf("%lld",&c[i][j]);
		}
	}
	for(int i=1;i<=n;++i) scanf("%lld",&d[i]); 
//	memset(e,-1,sizeof(e));		//这个初始化是 0 (从 -1 开始会很麻烦但不是不行) 
	memset(b,-1,sizeof(b));
	p[0]=p[1]=1;		//起点是 1 
	y[0]=y[1]=m;
}

void __turn()		//回合结算 
{
	if(h[0]&&h[1])
	{
		for(int i=1;i<=n;++i)
		{
			if(b[i]==1) y[1]+=d[i];
			if(b[i]==0) y[0]+=d[i];
		}	
		h[0]=h[1]=0;
	}
}

void __move()		//移动 
{
	while(k--)
	{
		p[t]++;		//路过的所有地方都要判(见样例解释) 
		if(p[t]>n) p[t]-=n; 
		if(b[p[t]]==t) 
		{
			y[t]+=a[p[t]];	//是自己的得钱					
		}
		if(b[p[t]]==(!t)) 
		{
			y[t]-=a[p[t]];	//不是自己的交钱 
			y[(!t)]+=a[p[t]]; 		
		}
		if(y[t]<0)		//判断是否结束,可以证明只有移动操作会把钱扣到负数 
		{
			t?puts("Renko"):puts("Merry");		//输出负的那个 
			exit(0);
		}
	}
}

void  __powerup()	//升级建筑 
{
	if(b[p[t]]==t||b[p[t]]==-1) 
	{
		for(int i=1;i<=k;++i)
		{
			if(e[p[t]]==l) return;		//这个写错位置就寄了 
			if(y[t]>=c[p[t]][e[p[t]]]) 
			{
				y[t]-=c[p[t]][e[p[t]]];
				a[p[t]]+=c[p[t]][e[p[t]]];		//升级
				e[p[t]]++;	    	//这个写错位置也寄 
				if(b[p[t]]==-1) b[p[t]]=t;		//购买 
			} 
		}
	}
}

#undef int
int main()
{
	__pre();
	//上面是初始化
	
	//开始游戏 
	while(scanf("%lld",&x)!=EOF)
	{
		scanf("%lld",&k);
		if(x==1) 
		{
			__turn();
			t=!t;		//切换行动方 
			h[t]=1;
			__move();
		}
		if(x==2)
		{
			__powerup(); 
		}
	}
	h[1]=h[0]=1;	//最后一回合也要结算(不然样例 2 会死) 
	__turn();
	printf("%lld %lld\n",y[1],y[0]);
}


代码(附调试过程中用到的东西)
#include<bits/stdc++.h>

using namespace std;
#define int long long		//竟然要开long long 

int n,m,q,l;		//格子数、初始资金、回合数、建筑物等级上限
int a[111];			//走到第 i 格时,如果是自己的则获得 a[i][j] 元,是对方的则支付 a[i][j] 元 
int c[111][111];	//第 i 格建筑升到 j+1 级所需价钱 
int d[111];			//每回合第 i 格建筑提供资金 
int b[111];			//第 i 格建筑属于谁(1=莲子/0=梅莉/-1=没有) 
int e[111];			//第 i 格建筑当前等级(初始为 -1)
int x,k;			//行动种类、行动次数(x=1 时切换行动方,行动方走到第 now+k 格;x=2 时当前行动方对第 i 格建筑升 k 级)
bool t;				//当前行动方(1=莲子/0=梅莉) 
int p[2]; 			//当前所在位置(1=莲子/0=梅莉) 
int y[2];			//当前持有的钱数(1=莲子/0=梅莉)
int h[2];			//判断是否进入下一回合(本回合两人都已行动过一次后 x==1 时进入下一回合) 

//带 test 的函数是调试的时候用的 

#define test_place() t?printf("Renko in the %lld.\n",p[t]):printf("Merry in the %lld.\n",p[t]);
#define test_money() printf("Renko has %lld yuan\n",y[1]),printf("Merry has %lld yuan\n",y[0]);

void test_got(int id,int mny)
{
	id?printf("Renko got %lld yuan\n",mny):printf("Merry got %lld yuan\n",mny);
}

void test_lost(int id,int mny)
{
	id?printf("Renko lost %lld yuan\n",mny):printf("Merry lost %lld yuan\n",mny);
}

void test_pwup(int pos,int lv)
{
	t?printf("Renko changes %lld to lv.%lld\n",pos,lv):printf("Merry changes %lld to lv.%lld\n",pos,lv);
}

void test_belong()
{
	printf("Renko: ");
	for(int i=1;i<=n;++i) if(b[i]==1) printf("%lld ",i);
	puts("");
	printf("Merry: ");
	for(int i=1;i<=n;++i) if(b[i]==0) printf("%lld ",i);
	puts("");
}

void __pre()	//初始化 
{
	scanf("%lld%lld%lld%lld",&n,&m,&q,&l);
	for(int i=1;i<=n;++i)
	{
		for(int j=0;j<l;++j)
		{
			scanf("%lld",&c[i][j]);
		}
	}
	for(int i=1;i<=n;++i) scanf("%lld",&d[i]); 
//	memset(e,-1,sizeof(e));					//这个初始化是 0 (从 -1 开始会很麻烦但不是不行) 
	memset(b,-1,sizeof(b));
	p[0]=p[1]=1;							//起点是 1 
	y[0]=y[1]=m;
}

void __turn()		//回合结算 
{
	if(h[0]&&h[1])
	{
//		test_money();
//		test_belong();
//		int g1=0,g2=0;
		for(int i=1;i<=n;++i)
		{
			if(b[i]==1) 
			{
				y[1]+=d[i];
//				g1+=d[i];
			}
			if(b[i]==0) 
			{
				y[0]+=d[i];
//				g2+=d[i];
			}
		}	
		h[0]=h[1]=0;
//		test_got(1,g1);
//		test_got(0,g2);
	}
}

void __move()		//移动 
{
	while(k--)
	{
		p[t]++;				//路过的所有地方都要判(见样例解释) 
		if(p[t]>n) p[t]-=n; 
//		test_place();
		if(b[p[t]]==t) 
		{
			y[t]+=a[p[t]];						//是自己的得钱
//			test_got(t,a[p[t]]);					
		}
		if(b[p[t]]==(!t)) 
		{
			y[t]-=a[p[t]];					//不是自己的交钱 
			y[(!t)]+=a[p[t]];
//			test_lost(t,a[p[t]]),test_got((!t),a[p[t]]); 		
		}
		if(y[t]<0)		//判断是否结束,可以证明只有移动操作会把钱扣到负数 
		{
			t?puts("Renko"):puts("Merry");		//输出负的那个 
			exit(0);
		}
	}
}

void  __powerup()		//升级建筑 
{
	if(b[p[t]]==t||b[p[t]]==-1) 
	{
		for(int i=1;i<=k;++i)
		{
			if(e[p[t]]==l) return;				//这个写错位置就寄了 
			if(y[t]>=c[p[t]][e[p[t]]]) 
			{
				y[t]-=c[p[t]][e[p[t]]];
				a[p[t]]+=c[p[t]][e[p[t]]];		//升级
//				test_pwup(p[t],e[p[t]]);
//				test_lost(t,c[p[t]][e[p[t]]]);
				e[p[t]]++;						//这个写错位置也寄 
				if(b[p[t]]==-1) b[p[t]]=t;		//购买 
			} 
		}
	}
}

#undef int
int main()
{
	__pre();
	//上面是初始化
	
	//开始游戏 
	while(scanf("%lld",&x)!=EOF)
	{
		scanf("%lld",&k);
		if(x==1) 
		{
			__turn();
			t=!t;			//切换行动方 
			h[t]=1;
			__move();
		}
		if(x==2)
		{
			__powerup(); 
		}
//		test_money(); 
//		printf("%lld %lld\n",y[1],y[0]);
	}
	h[1]=h[0]=1;			//最后一回合也要结算(不然样例 2 会死) 
	__turn();
	printf("%lld %lld\n",y[1],y[0]);
}


posted @ 2024-05-16 21:25  Miqa  阅读(25)  评论(0编辑  收藏  举报