您的位置:首页 > 理论基础 > 计算机网络

ACM练级日志:ACM2013 南京网络赛

2014-08-09 22:19 267 查看
这篇日志是用来反省用的…… 本场比赛我们总共A3题,我1题,ztb2题,但是因为我的博弈树搜索卡了,导致我们没能上第四道题,虽然前面三题很顺利,但是这致命的一题还是卡死了我们的队伍。

先说说题吧,1004顺利搞定了,它的题意是这样的:有很多人,他们之间某些人是认识的,但是认识不具有传递性,而且认识是单向的;现在问能不能把他们分成两组,使得每组里面组员两两之间都互相认识。

我提出了一个正确的思路:既然A认识B,B不认识A,就不能把他俩放一块,那么这幅图里所有单向边都没有意义。但是之后的如何分组却是经过ztb提示才想出来的:因为只需要分两个组,所以不互相认识的人肯定分别在两个组里,那么只要把不认识的人之间连边,然后BFS进行01染色,看能否染成就行…… 似乎这种两组的问题总是能和BFS染色联系起来。

然后说说重点吧,我被卡死的那道博弈树。1006大概说的是这么一个事:你有一个3x3的九宫格,有两个人玩这么一个游戏:两个人轮流填上九宫格的边,如果你填的这一条边加上已经存在了的边形成了一个1x1的小正方形,你就得一分,如果形成了两个你就得两分。现在给出现有状态,问谁会赢。

由于最多只需要填12条边,所以这是博弈树搜索,但是我之前只写过一个错误的博弈树搜索,经过这次之后,我觉得非常有必要自此记住博弈树搜索怎么写:

博弈树要做的事情就是我拿着我目前的状态,去用DFS判断这个状态是我的必败态还是必胜态。注意!每次在看的时候,都是以当时走棋的那个人的视角去看的,所有的决策的视角都是当时走棋的那个人。

其次,如何判断必胜态必败态?当我要走棋的时候,我就先试试走所有我能走的棋,然后换你进行DFS,如果有一个状态你返回来的是false,意思就是我走这一步就到你的必败态了,那我就撤销我这步所走的棋,然后返回true,表示这是我的必胜态。注意一定要先撤销自己走的棋!!别特别激动的也不回溯直接就返回结果了。

最后,如果我看完了所有的状态你都是必胜态,那这个就是我的必败态了。

以上是博弈树的写法,不是什么“奇层取与,偶层取或”,每一层都是一样的,你甚至不用关心当前是第几层。当然为了调试方便,我觉得还是加上好。

递归的边界条件就是当前状态一眼就能看出是必胜态还是必败态了,直接在开头告诉结果就行。

一般这种博弈双方都是要记录分数的,分数还是放到参数里面传比较保险,每次传的时候把你我的分数调换一下就行了;不然的话忘了回溯事儿就大了。

差不多博弈树就说这些吧,一会把这道题的DFS部分贴上来当模板了……

然后说说这道题本身,我觉得维护的部分还是做得挺成功的,方法很直观,把号换成第几行第几列的坐标形式,计分的时候判断一个矩形的4边是否都有;回溯的时候判断如果一个矩形已经被记过分了,但是有一边不存在的时候,就告诉它要扣一分。只不过这道题因为只有24条边,所以可以用一个int表示,这样就能记忆化了,这个是没有想到的,记上一笔免得下次需要用。

本题调了半天,首先是我对博弈树的认识有误,一开始按照奇数层偶数层去写了,还记了当前是谁走,直接把自己绕晕了;然后是经过ztb提醒,不再记录目前轮到谁走,也把计分放到参数里面去计了。比赛的时候只查出了这两个错,之后我查的时候又发现两个:首先就是,当你已经看到你目前所处状态的某一步棋能直接把对方干掉的时候,别一高兴直接返回true,先回溯!!! 然后就是直接看胜败的边界条件不对,我写的是==5,但是完全有可能有人4分直接蹦到6分,然后就完蛋了。

测试也是,这道题不太容易测试,一个好的测试方法就是加满24条边,然后一条一条删。另外虽然我所有测试的用例结果都对,但是我是从它打出的日志判断到底哪里出了问题的。这也算是一个经验吧……不一定用例算对,就一定是对的,看看调试信息也许也会有很大的收获,

长春站是最后的希望,就算听说对手们都很强也没关系,我一定不会再在手里面卡住应该过去的题了。

博弈树DFS一个例子:

bool DFS(int depth, int my_s, int your_s)
{
////TEST
//cout<<"depth: "<<depth<<" my_s: "<<my_s<<" your_s: "<<your_s<<endl;
if(my_s>=5)
return true;
else if(your_s>=5)
return false;

int i,j;
for(i=1;i<=4;i++)
{
for(j=1;j<=4;j++)
{
//TEST
//if(i==1 && j==4)
//stop();

if(j<=3 && map[i][j][i][j+1] == 0 )
{
//TEST
//  cout<<"adding "<<i<<" "<<j<<" "<<i<<" "<<j+1<<endl;

my_s+=addedge2(i,j,i,j+1);

bool tmp=DFS(depth+1,your_s, my_s);

my_s-=deledge(i,j,i,j+1);

if(tmp==false)
return true;
}

if(i<=3 && map[i][j][i+1][j] == 0 )
{
//TEST
//cout<<"adding "<<i<<" "<<j<<" "<<i+1<<" "<<j<<endl;

my_s+=addedge2(i,j,i+1,j);

bool tmp=DFS(depth+1,your_s, my_s);

my_s-=deledge(i,j,i+1,j);

if(tmp==false)
return true;

}
}
}
return false;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: