Luogu P2482 [SDOI2010]猪国杀
这道题在模拟界地位不亚于Luogu P4604 [WC2017]挑战在卡常界的地位了吧。
早上到机房开始写,中间因为有模拟赛一直到1点过才正式开始码。
一边膜拜CXR dalao一边写到3点左右,然后调啊调
最后发现杀死反猪抽的牌并没有被杀死它的人抽走(大雾),4点左右终于是写完了
看完题目(看都要10min)感觉这肯定不是什么建图跑XX算法或者套一个数据结构的题
然而数据范围也很默契,猪和牌的数量都不多,所以我们祭出被我们遗弃的暴力算法——模拟。
题目意思都不多说了,以下讲一下大致的思路:
- 每个猪应该有两个身份要记录。一个是真实身份,另一个是当前在游戏中目前的身份,即有可能是未知和类反猪
- 关于猪本身一些手牌,血量,有没有武器,下一头猪(因为可能有猪会死掉)等要记录的就不多说了
- 每个回合里分别便利当前猪的所有手牌并判断是否可以打出(没有目标自然是不能出的)
- 判断每个行动以及更新在此过程中可能会被更新的身份信息
- 无懈可击的情况要特别判断,写一个递归即可(实现看代码)
大致思路就是这样了,为了造福人类还是说一下这道题的坑点:
- 题目中描述反猪为
AP
,实际上是FP
(看样例就知道了) - 题目里说“数据保证牌的数量够用。”就是在扯淡。如果没牌要一直摸最后一张牌
MP
干掉ZP
后武器也得弃了- 无懈去无懈别人的无懈时要注意和原来的行为性质刚好相反(因为只有敌人会无懈你的无懈)
- 一头猪在自己回合也会GG(决斗把自己玩死),同时在自己回合也可能摸牌(
FP
和你决斗然后它GG了) - 除了桃之外的牌其他的牌在打出后都得重新扫描手牌(因为可能因为有武器使得之前的杀也可以用了,或者是由于一些猪身份的公开使得之前的一些牌有目标了)
- 只有
MP
会攻击类反猪,ZP
是不会对类反猪表敌意的 - 放AOE技能时可能会一次干掉很多人,就会产生比如一回合摸许多牌的情况
- 同上,
MP
用AOE技能时要注意结算的顺序,尤其是杀了ZP
又杀死FP
会导致手上还有牌,而先杀死FP
再杀ZP
就一张牌都没有了 MP
或所有FP
死了游戏立即结束,意味着有牌摸的也不用摸了
大致就是这些了,还有强烈建议写的时候打点注释上去省的到时候自己都不知道自己在写什么心态爆炸
贴一下CODE(注释都是写的时候打上去的),如果要看超级详细的解析CODE的移步CXR dalao's blog
CODE
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#define RI register int
#define GC(x) P[x].hand_cards[++P[x].tot]=getcard(); //x摸牌,太长了所以用下define
using namespace std;
const int M=2005;
class FileInputOutput
{
private:
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
#define S 1<<21
char Fin[S],Fout[S],*A,*B; int Ftop;
public:
FileInputOutput() { A=B=Fin; }
inline void pc(char ch)
{
Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch);
}
inline void gc(char &ch)
{
while (!isalpha(ch=tc()));
}
inline void ps(const char *s)
{
int len=strlen(s); for (RI i=0;i<len;++i) pc(s[i]);
}
inline void read(int &x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
}
inline void Fend(void)
{
fwrite(Fout,1,Ftop,stdout);
}
#undef tc
#undef S
}File;
struct Pig
{
int type,status,tot,hp,nxt; char hand_cards[M]; //hand_cards手牌,若为'U'则表示这张牌出掉了
//type表示真实身份(1:MP;2:ZP;3:FP),status表示表露出的身份(0:未知;1:MP;2:ZP;3:FP:4:类反)
bool isZ,isalive; //isZ表示是否装备猪哥连弩,isalive表示是否存活
}P[12]; int n,m,cnt,now; char cards[M],ch;
inline char getcard(void)
{
if (cnt<m) return cards[++cnt]; else return cards[cnt];
}
inline int getnext(int x) //找下一头猪,可以路径压缩
{
return P[P[x].nxt].isalive?P[x].nxt:P[x].nxt=getnext(P[x].nxt);
}
inline int find(int x,char y) //查找x是否有牌y,有返回位置,否则返回-1
{
for (RI i=1;i<=P[x].tot;++i) if (P[x].hand_cards[i]==y) return i; return -1;
}
inline void Endgame(void) //游戏结束,输出结果
{
if (P[1].isalive) File.ps("MP\n"); else File.ps("FP\n");
for (RI i=1;i<=n;++i)
{
if (!P[i].isalive) { File.ps("DEAD\n"); continue; }
for (RI j=1;j<=P[i].tot;++j) if (P[i].hand_cards[j]!='U')
File.pc(P[i].hand_cards[j]),File.pc(' '); File.pc('\n');
}
File.Fend(); exit(0);
}
inline void Hurt(int x,int y) //x对y造成了一点伤害
{
if (--P[y].hp) return; int pos=find(y,'P');
if (~pos) return (void)(++P[y].hp,P[y].hand_cards[pos]='U');
P[y].tot=-1; P[y].isalive=0; if (P[y].type==1) Endgame();
if (P[y].type==2&&P[x].type==1) P[x].tot=0,P[x].isZ=0;
if (P[y].type!=3) return; bool isFP=0; RI fr=0,nxt=1;
for (;fr!=nxt;nxt=getnext(nxt),fr=1) if (P[nxt].type==3) { isFP=1; break; }
if (!isFP) Endgame(); GC(x); GC(x); GC(x);
}
inline int indentfy(int x,int y) //鉴定x,y的关系(根据跳的情况判断,注意MP要特判
//(1:同伙;2:敌人;3:y身份未知)
{
if (!P[y].status) return 3; switch (P[x].type)
{
case 1:
if (P[y].status==1||P[y].status==2) return 1;
if (P[y].status==3||P[y].status==4) return 2;
break;
case 2:
if (P[y].status==1||P[y].status==2) return 1;
if (P[y].status==3) return 2; if (P[y].status==4) return 3;
break;
case 3:
if (P[y].status==1||P[y].status==2) return 2;
if (P[y].status==3) return 1; if (P[y].status==4) return 3;
}
return 3;
}
inline void Make_Friendly(int x,int y) //x向y献殷勤,要更新关系
{
if ((P[y].status==1||P[y].status==2)&&P[x].type!=1) P[x].status=2;
if (P[y].status==3) P[x].status=3;
}
inline void Make_Antily(int x,int y) //x向y表敌意,也要更新关系
{
if (P[y].status==1||P[y].status==2) P[x].status=3;
if (P[y].status==3&&P[x].type!=1) P[x].status=2;
}
inline void K(int x,int y) //x向y打出一张杀
{
Make_Antily(x,y); int pos=find(y,'D');
if (~pos) P[y].hand_cards[pos]='U'; else Hurt(x,y);
}
inline bool J(int x,int y,int opt) //依次决定对于x对y打出的锦囊是否有人响应无懈
//opt表示这次无懈行为是献殷勤(1)还是表敌意(2)
{
for (RI nxt=x,fr=0;nxt!=fr;nxt=getnext(nxt),fr=x)
{
if (indentfy(nxt,y)!=opt) continue;
int pos=find(nxt,'J'); if (~pos)
{
P[nxt].hand_cards[pos]='U';
if (opt==1) Make_Friendly(nxt,y); else Make_Antily(nxt,y);
return J(nxt,y,3-opt)^1;
}
}
return 0;
}
inline void F(int x,int y) //x向y进行决斗
{
Make_Antily(x,y); if (J(x,y,1)) return;
if (P[x].type==1&&P[y].type==2) return Hurt(x,y);
int pos; for (;;)
{
pos=find(y,'K'); if (~pos) P[y].hand_cards[pos]='U'; else return Hurt(x,y);
pos=find(x,'K'); if (~pos) P[x].hand_cards[pos]='U'; else return Hurt(y,x);
}
}
inline void N(int x) //x打出南猪入侵
{
for (int nxt=getnext(x);nxt!=x;nxt=getnext(nxt))
{
if (J(x,nxt,1)) continue; int pos=find(nxt,'K');
if (~pos) { P[nxt].hand_cards[pos]='U'; continue; }
if (P[nxt].type==1&&!P[x].status) P[x].status=4; Hurt(x,nxt);
}
}
inline void W(int x) //x打出万箭齐发
{
for (int nxt=getnext(x);nxt!=x;nxt=getnext(nxt))
{
if (J(x,nxt,1)) continue; int pos=find(nxt,'D');
if (~pos) { P[nxt].hand_cards[pos]='U'; continue; }
if (P[nxt].type==1&&!P[x].status) P[x].status=4; Hurt(x,nxt);
}
}
inline void Play(void) //一回合
{
GC(now); GC(now); bool iskilled=0; int nxt;
for (RI i=1;i<=P[now].tot;++i)
{
char &opt=P[now].hand_cards[i]; switch (opt)
{
case 'K':
if (iskilled&&!P[now].isZ) break;
if (indentfy(now,nxt=getnext(now))==2) { opt='U'; iskilled=1; K(now,nxt); i=0; break; } //是敌对关系才能杀
break;
case 'F':
if (P[now].type==3) { opt='U'; F(now,1); i=0; break; } //FP优先杀MP
for (nxt=getnext(now);nxt!=now;nxt=getnext(nxt))
if (indentfy(now,nxt)==2) { opt='U'; F(now,nxt); i=0; break; } //按顺序找人决斗
break;
case 'N':
opt='U'; N(now); i=0; break;
case 'W':
opt='U'; W(now); i=0; break;
case 'P':
if (P[now].hp<4) opt='U',++P[now].hp; break;
case 'Z':
opt='U'; P[now].isZ=1; i=0; break;
}
}
}
#undef GC
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
RI i,j; for (File.read(n),File.read(m),i=1;i<=n;++i)
{
File.gc(ch); P[i].type=ch=='M'?1:(ch=='Z'?2:3); if (P[i].type==1) P[i].status=1;
P[i].tot=4; for (File.gc(ch),j=1;j<=4;++j) File.gc(P[i].hand_cards[j]);
if(i^n) P[i].nxt=i+1; else P[i].nxt=1; P[i].isalive=1; P[i].hp=4;
}
for (i=1;i<=m;++i) File.gc(cards[i]); for (now=1;;now=getnext(now)) Play(); return 0;
}
Luogu P2482 [SDOI2010]猪国杀的更多相关文章
- [洛谷P2482][SDOI2010]猪国杀
题目大意:猪国杀,又一道大模拟题 题解:模拟,对于一个没有玩过三国杀的人来说,一堆细节不知道,写的十分吃力 卡点:无数,不想说什么了,这告诉我要多玩游戏 C++ Code: #include < ...
- 洛谷P2482 [SDOI2010]猪国杀——题解
猪国杀,模拟题的一颗耀眼的明珠,成长大牛.锻炼码力必写题! 模拟题没什么思维难度.只要按部就班地去做就是.模拟简单在这,难也在这.因为题面巨长,条件巨多,忽疏一点都有可能全盘皆输.故推荐考试时碰见了, ...
- 并不对劲的bzoj1972:loj2885:p2482[SDOI2010]猪国杀
题目大意 只能放链接了. 题目中有一点没说:并不是保证牌够用,而是在牌不够用时反复抽最后一张牌. 题解 发现玩家的数量比较少,所以可以不太在意时间够不够用. 考虑三件事:1.基本操作,如摸牌.出牌.玩 ...
- Luogu2482 [SDOI2010]猪国杀 ---- 模拟
Luogu2482 [SDOI2010]猪国杀 题意 ...... https://www.luogu.org/problemnew/show/P2482 总结 首先说一下代码的构思: 首先确定了所有 ...
- [BZOJ 1972][Sdoi2010]猪国杀
1972: [Sdoi2010]猪国杀 Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 364 Solved: 204[Submit][Status][D ...
- 洛谷 P2482 loj #2885 [SDOI2010]猪国杀 题解【模拟】【贪心】【搜索】
好玩的模拟题. 以后要经常写模拟题鸭 题目描述 游戏背景 <猪国杀>是一种多猪牌类回合制游戏,一共有\(3\)种角色:主猪,忠猪,反猪.每局游戏主猪有且只有\(1\)只,忠猪和反猪可以有多 ...
- BZOJ1972:[SDOI2010]猪国杀
我对模拟的理解:https://www.cnblogs.com/AKMer/p/9064018.html 题目传送门:https://www.lydsy.com/JudgeOnline/problem ...
- 【BZOJ1972】[SDOI2010] 猪国杀(恶心的大模拟)
点此看题面 大致题意: 让你模拟一个游戏猪国杀的过程. 几大坑点 对于这种模拟题,具体思路就不讲了,就说说有哪些坑点. 题面有锅,反猪是\(FP\). 数据有锅,牌堆中的牌可能不够用,牌堆为空之后需一 ...
- Bzoj1972: [Sdoi2010]猪国杀 题解(大模拟+耐心+细心)
猪国杀 - 可读版本 https://mubu.com/doc/2707815814591da4 题目可真长,读题都要一个小时. 这道题很多人都说不可做,耗时间,代码量大,于是,本着不做死就不会死的精 ...
随机推荐
- Android Studio列表用法之一:ListView图文列表显示(实例)
前言: ListView这个列表控件在Android中是最常用的控件之一,几乎在所有的应用程序中都会使用到它. 目前正在做的一个记账本APP中就用到了它,主要是用它来呈现收支明细,是一个图文列表的呈现 ...
- 自己搭建git 代码服务器
使用git服务器的工程师都需要生成一个ssh的公钥 ~/.ssh$ ssh-keygen Generating public/private rsa key pair. …………………… ……………… ...
- UML类图关系图解
一.类结构 在类的UML图中,使用长方形描述一个类的主要构成,长方形垂直地分为三层,以此放置类的名称.属性和方法. 其中, 一般类的类名用正常字体粗体表示,如上图:抽象类名用斜体字粗体,如User:接 ...
- 慕学在线网0.5_xadmin的全局配置
全局配置包括了以下修改: 开启主题功能: 修改左上角的"django Xadmin"和主界面的"我的公司": App菜单收叠: App名字修改(汉化). 1.把 ...
- ER模型试题
M公司为了便于开展和管理各项业务活动,提高公司的知名度和影响力,拟构建一个基于网络的会议策划系统. [需求分析结果] 该系统的部分功能及初步需求分析的结果如下 : (1)M公司旗下有业务部.策划部和其 ...
- python格式化字符串format函数
1. format可以接受无限个的参数,位置可以不按顺序: In [1]: "{} {}".format("hello","world") ...
- 洗礼灵魂,修炼python(44)--巩固篇—反射之重新认识hasattr,gettattr,setattr,delattr
不急着进入正题.先动手完成一个小程序: 设计一套简单的服务开启关闭程序,每次开启或关闭都得打印服务当前的状态: class Server(object): def __init__(self): se ...
- 【 PostgreSQL】查询某模式下所有表的分布键信息
想看下某模式下所有表创建的分布键是否合理,查找系统表文档拼出如下sql,亲们如果有更好的sql或者意见欢迎留言! SELECT aaa.nspname AS "模式名", ...
- 字典Key值为变量
m='aaa4a' d = dict(name=m) print d['name']
- 如何在windows下使用pip安装
首先电脑已经安装好了python 找到python的安装目录,接着找到pip.exe,一般而言它会在Scripts文件夹下,我这里选择的是pip2.7.exe 接下来,win+r,输入cmd,回车打开 ...