【题解】游戏 (2019.08.01纪中【NOIP提高组】模拟 B 组T1) DP 博弈论_小猴和朋友正在玩一个游戏,初始时,在一个 × n×n 的棋盘上放置着_楚颜a的博客-程序员秘密

技术标签: 题解  博弈论  动态规划  

题目来源:中山纪念中学

题目描述:

Alice和Bob在玩一个游戏,游戏是在一个N*N的矩阵上进行的,每个格子上都有

一个正整数。当轮到Alice/Bob时,他/她可以选择最后一列或最后一行,并将其删除,但

必须保证选择的这一行或这一列所有数的和为偶数。如果他/她不能删除最后一行或最后一

列,那么他/她就输了。两人都用最优策略来玩游戏,Alice先手,问Alice是否可以必胜?

输入:

第一行:T,表示数据组数

对于每组数据的第一行:N

接下来N行,每行N个数,描述这个矩阵

输出:

如果Alice必胜输出W,否则输出L

输入样例

2
2
2 4
6 8
3
5 4 2
1 5 9
7 3 8

输出样例:

L
W

数据范围:

100%数据满足

1<=N<=1000

保证每一行或每一列的和不会超过2*10^9

1<=T<=5

30%数据满足

1<=N<=5

50%数据满足

1<=N<=100

70%数据满足

1<=N<=500

思路:

暴力做法:模拟 50分
1、用a数组存原矩阵,用b数组存原矩阵“列“”的前缀和,用c数组存原矩阵“行”的前缀和,方便快速判断某一列或某一行可不可以删除
2、从右下角开始模拟删除,如果当前行或当前列可以删除,累加删除次数,否则return
3、如果删除次数是奇数,则Alice必输,如果是偶数则必赢

50分代码:

#include<bits/stdc++.h>
using namespace std;
long long t,n,a[1001][1001],b[1001][1001],c[1001][1001],pd=1;
void search(int i,int j)
{
    
	if (b[i][j]%2!=0&&c[i][j]%2!=0||i==0||j==0) return;
	if (b[i][j]%2==0) pd++,search(i-1,j);
	if (c[i][j]%2==0) pd++,search(i,j-1);
}
int main()
{
    
	pd=1;
	cin>>t;
	for (int k=1;k<=t;k++)
	{
    
		cin>>n;
		for (int i=0;i<=n;i++)
		for (int j=0;j<=n;j++) b[i][j]=0,c[i][j]=0;
		for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
		{
    
			cin>>a[i][j];
			b[i][j]=b[i][j-1]+a[i][j];
			c[i][j]=c[i-1][j]+a[i][j];
		}
		search(n,n);
		if (pd%2!=0) cout<<"L"<<endl;
		else cout<<"W"<<endl;
	}
	return 0;
}

正解:DP 100分
听说这是博弈论?噢~原来这就是博弈论
f[i][j]表示从右下角为i,j坐标开始删除Alice先手的输赢状况,1为必赢,0为必输,我们只要把对方置为必输状况就可以赢了,判断当前输赢状况分三种情况
1、当f[i][j]左边和上边都是必赢时,无论当前怎么删,到了对方就是必赢,所以我方必输
2、当只有一个是必赢时,判断可否删除必赢的那一行或列,将对手置于必输状况,如果可以删除,那么当前位置就必赢
3、当两个都必输时,任意删除偶数行或偶数列,都可以将对手置于必输状况,如果都删不了,那么就必输
如果还是不太理解的话,可以将f数组画出来,以第二个矩阵为例子:
在这里插入图片描述

最后的f[n][n]为1,必赢,所以输出W

AC代码:

#include<bits/stdc++.h>
using namespace std;
int t,n,a[1001][1001],b[1001][1001],c[1001][1001],f[1001][1001];
int main()
{
    
    cin>>t;
    for (int k=1;k<=t;k++)
    {
    
        cin>>n;
        for (int i=0;i<=n;i++)
        for (int j=0;j<=n;j++) f[i][j]=0,b[i][j]=0,c[i][j]=0;  
        for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
        {
    
            cin>>a[i][j];
            b[i][j]=b[i][j-1]+a[i][j];
            c[i][j]=c[i-1][j]+a[i][j];//前缀和
        }   
        if (a[1][1]%2==0) f[1][1]=1; else f[1][1]=0; //初始化 
        for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
        {
    
            if (f[i-1][j]==0&&f[i][j-1]==0)
              if (b[i][j]%2==0||c[i][j]%2==0) f[i][j]=1;//只要前两个都是零并且可以删,那么这个位置必赢 
            if (f[i-1][j]==0&&f[i][j-1]==1)
              if (b[i][j]%2==0) f[i][j]=1;
            if (f[i-1][j]==1&&f[i][j-1]==0)
              if (c[i][j]%2==0) f[i][j]=1;  //前两个一个0一个1,对应的可以删就必赢 
        }  
        if (f[n][n]==1) cout<<"W"<<endl; //最后是1,必赢 
        else cout<<"L"<<endl;
    }
    return 0;
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_45485187/article/details/98841739

智能推荐

vue之vuex的五个属性_jh1906338271的博客-程序员秘密

1.官方解释Vuex是一个专为Vue.js应用程序开发的状态管理模式。然后Vuex里面有五个特别重要的属性,分别是state,mutations,actions,getters,modules。2.state放置状态相关的信息,vue是使用单一状态树的,也就是单一数据源,也就是说我们的state只能有一个3.mutationsmutations其实就相当于我们vue里面的methods...

bzoj4003 [JLOI2015]城池攻占(左偏树)_bzoj 4003_Icefox_zhx的博客-程序员秘密

左偏树就是满足堆性质,且满足左子树深度不小于右子树深度的二叉树。 这样右子树深度是O(logn)O(logn)O(logn)的。 可以用来做可合并堆。 复杂度O(nlogn)O(nlogn)O(nlogn)此题就是裸题啦,维护一个乘法标记和加法标记即可。因为乘的是一个正数,因此大小关系不变。从底向上合并起来即可。#include &amp;lt;bits/stdc++.h&amp;gt;using...

bzoj千题计划188:bzoj1923: [Sdoi2010]外星千足虫 (高斯—若尔当消元法解异或方程组)..._weixin_30322405的博客-程序员秘密

http://www.lydsy.com/JudgeOnline/problem.php?id=1923#include&lt;cstdio&gt;#include&lt;cstring&gt;#include&lt;iostream&gt;#include&lt;bitset&gt;using namespace std;int n,m;bitset&lt;...

每日一题:leetcode80.删除有序数组中的重复元素贰_月本_诚的博客-程序员秘密

题目描述题目分析又是一道贴错标签的简单题,很明显的双指针,我的做法是用两个变量保存是否需要记录,官方题解的做法是直接判断,人家的高明一些class Solution {public: int removeDuplicates(vector&lt;int&gt;&amp; nums) { int n = nums.size(); if (n &lt; 3) return n; int i = 0, j = 0, cnt = 0, now = I

51nod 1042 数字0-9的数量(数位dp)_算球?的博客-程序员秘密

做法同51nod 1009 数字1的数量 相差不多,不过查询0的时候要特别处理,做的时候拿别人代码调了好久才看懂。。。参考的:http://blog.csdn.net/f_zyj/article/details/52082449#include <iostream>#include <algorithm>using namespace std;typedef long long ll;ll

C# 将多个图片合并成TIFF文件的两种方法_dotNET跨平台的博客-程序员秘密

最近需要用到TIF格式的文件,研究了一段时间,终于有点结果了,发现两种方式,第一种是使用BitMiracle.LibTiff.NET,直接在Nuget上安装即可,第二种是使用RasterE...

随便推点

一个图像加密的应用场景小程序_bj21002000的博客-程序员秘密

最近参加一个图像信息安全与人工智能结合的比赛,评审后专家说要有一个应用场景,做了一个基于加密图像的身份认证场景程序,pyqyt5写的from PyQt5.QtWidgets import *import sysfrom PyQt5.QtCore import Qtfrom PyQt5.QtGui import *from PyQt5.QtWidgets import *from PyQt5.QtCore import *from qtconsole.qt import QtGuiimpor

零基础学python知乎-编程零基础应当如何开始学习 Python?_weixin_37988176的博客-程序员秘密

这个问题下面这么多人推荐了这么多 Python 资源,估计零基础新手看到了会眼花缭乱吧。作为非计算机专业出身、自学编程的过来人,我知道想找到一份适合自己的入门教程不容易。不如就在这里分享一下,如何鉴别一份 Python 教程是否适合新手。鉴别要点1:这份教程是否支持 Python3?在2020年,Python 核心团队就会停止支持 Python 2 了。目前不少主流库的新版本也停止支持了 Pyth...

html之如何让多个并列的div居中显示_多个div并排居中_Quincy379的博客-程序员秘密

<div id="testContainer"> <div><img src="1.png"></div> <div><img src="1.png"></div> <div><img src="1.png"></div> <div><img src="1.png"></div> <div><img src="1.png"></div> <div><i

@Autowired和@Resource的区别是什么?_独步秋风的博客-程序员秘密

作者:wuxinliulei链接:https://www.zhihu.com/question/39356740/answer/80926247。@Autowired 与@Resource:1、@Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。2、@Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对...

Xcode基本设置系列和Xcode报错解决方案_dazhi121812的博客-程序员秘密

1, arc机制中调用非arc文件。Xcode——&gt;Project-&gt;Build Phases,将需要非arc文件更改为:"-fno-objc-arc" ,该参数可以启用手工管理引用计数的模式。http://www.cocoachina.com/bbs/read.php?tid=153926二,限制只能竖屏展示修改info.plist ,找...

设置linux系统时间为北京时间_博享未来的博客-程序员秘密

删除自带的localtimerm -rf /etc/localtime 创建软链接到localtimeln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime查看时间date

推荐文章

热门文章

相关标签