ZOJ-搜索专题

news/2024/7/20 20:23:12 标签: 深度优先, 图论, 算法

1002

  • 题意
    在这里插入图片描述
    在这里插入图片描述
  • 思路

深搜,每个格子都搜一遍。技巧dfs(cnt,ans)dfs(第几个格子,答案);

  • 代码
#include <iostream>

using namespace std;

int n,i,j,ans;
char s[5][5];

int c_put(int n,int  m)
{
    for (i = n-1;i >= 0;i --) {
        if (s[i][m] == 'O')
            return 0;
        if (s[i][m] == 'X') 
            break;
    }
    for (j = m-1;j >= 0;j --) {
        if (s[n][j] == 'O')
            return 0;
        if (s[n][j] == 'X')
            break;
    }
    return 1;
}

void dfs(int k,int num)
{
    int x,y;
    if (k == n*n) {
        if (num > ans) {
            ans = num;
        }
        return ;
    }
    else {
        x = k/n;
        y = k%n;
        if (s[x][y] == '.'&&c_put(x,y)) {
            s[x][y] = 'O';
            dfs(k+1,num+1);
            s[x][y] = '.';
        }
        dfs(k+1,num);
    }
}
int main()
{
    while (cin>>n&&n) {
        ans = 0;
        for (i = 0;i < n; i++) {
            for (j = 0;j < n;j ++) 
                cin>>s[i][j];
        }
        dfs(0,0);
        cout<<ans<<endl;
    }
    return 0;
}

1003

  • 题意

在每年的6月1日儿童节,电视上都会有一个名为 "撞气球 "的游戏。 规则非常简单。 地上有100个贴有标签的气球,数字为1到100。 在裁判员喊出 "开始吧!"之后,两位选手开始时的分数都是 “1”,他们竞相用脚去撞气球,同时,他们的分数要乘以他们所撞气球上写的数字。 一分钟后,小观众们被允许把剩下的气球拿走,每个参赛者报告他/她的分数,即他/她撞破的气球上的数字的乘积。 非官方的赢家是宣布最高分数的选手。
但不可避免的是,会出现争议,因此在争议解决之前,不会确定正式的赢家。 声称分数较低的选手有权质疑其对手的分数。 得分较低的选手被认为是说了实话,因为如果他(她)要对自己的分数撒谎,他(她)肯定会想出一个更大更好的谎言。 如果分数较高的玩家的分数不能被挑战者撞碎的气球所达到,则挑战成功。 因此,如果挑战成功,声称分数较低的玩家获胜。

因此,例如,如果一个玩家声称得到343分,另一个声称得到49分,那么显然第一个玩家在撒谎;得到343分的唯一方法是撞毁标有7和49的气球,而得到49分的唯一方法是撞毁标有49的气球。 由于这两个分数都需要撞毁标有49的气球,那么声称得到343分的人就被认为是在撒谎。

另一方面,如果一个人声称得了162分,另一个人声称得了81分,那么两个人都有可能说的是实话(例如,一个人撞坏了2、3和27号气球,而另一个人撞坏了81号气球),所以挑战不会被支持。

顺便说一下,如果挑战者在计算他/她的分数时犯了一个错误,那么挑战将不会被支持。例如,如果一个玩家声称10001分,另一个声称10003分,那么显然他们都没有说实话。在这种情况下,挑战将不会被支持。

不幸的是,任何愿意担任撞气球游戏裁判的人都有可能在炎热的气氛中过度兴奋,不能合理地期望她进行裁判所需的复杂计算。 因此,需要你,清醒的程序员,提供一个软件解决方案。

  • 思路
    搜索,看看a,b假设a>b;是否都能够得到,如果a不能,那么就是b胜。
    否则就是a胜
    关键代码:
if (b == 1) {
        bTrue = 1;
        if (a == 1) aTrue = 1;
 }

这样aTrue 判断是在b(小数)已经可以的情况下。

  • 代码
#include <cstdio>
#include <iostream>
#include <cstring>

using namespace std;

bool aTrue,bTrue;

void judge(int a,int b,int  p)
{
    if (b == 1) {
        bTrue = 1;
        if (a == 1) aTrue = 1;
    }
    if (p == 1||(aTrue == 1&&bTrue == 1))
        return ;
    if (a%p == 0)
        judge(a/p,b,p-1);
    if (b%p == 0) 
        judge(a,b/p,p-1);
    judge(a,b,p-1);
}

int main()
{
    int a,b;
    while (scanf("%d%d",&a,&b) != EOF) {
        if (a < b)
            swap(a,b);
        aTrue = false;
        bTrue = false;
        judge(a,b,100);
        if (!aTrue && bTrue) {
            printf("%d\n",b);
        } else {
            printf("%d\n",a);
        }
    }
}

1031

  • 题意

下面的左图是用2(34)(=24)根火柴棒做成的一个完整的33格。所有火柴棒的长度都是一。你可以在网格中找到许多不同大小的正方形。一个正方形的大小就是它的边的长度。在左图所示的网格中,有9个大小为1的正方形,4个大小为2的正方形,1个大小为3的正方形。

如左图所示,完整的网格中的每根火柴棒都有一个独特的编号,从左到右、从上到下分配。如果你从完整的网格中抽出一些火柴棒,那么网格中的一些方格就会被破坏,这就导致了一个不完整的33号网格。右图显示的是除去三根编号为12、17和23的火柴棒后的不完整的33网格。这一移除行为破坏了5个大小为1的方格,3个大小为2的方格,以及1个大小为3的方格。因此,这个不完整的网格没有大小为3的方格,但仍有4个大小为1的方格和1个大小为2的方格。
在这里插入图片描述
作为输入,你将得到一个由不超过2n(n+1)根火柴棍组成的(完整或不完整的)nn网格,而自然数n<=5。你的任务是计算取出的火柴棒的最小数量,以破坏输入的nn个网格中的所有方格。

  • 思路
    此问题可以转化为一个图论的问题,把火柴看作另A类结点,正方形看作B类结点。
    如果某根火柴在某个正方形的边上,那么我们就往这相应的两个结点添加一条边。
    这样,问题转化为求该图中,最少用多少A类结点可以覆盖所有的B类结点。
    当n=5时,A类结点数为:2n(n+1)=60;B类结点数为:n(n+1)(2n+1)/6=55。
    可以见得,B类结点可以直接通过一个64位整型类储存。利用位运算,可以大大加快搜索速度。做法具体如下:
    (1) 若有边(i, j)(分别属于A、B类结点,下同),则Aij = 0;否则Aij = 1;
    (2) 对于每个确定的i,将Aij二进制编码至Bi中;
    (3) 除去数据中没有的Bi,并编码初始状态st;
    (4) 对于Bi按照可覆盖点数排序(优化1);
    (5) 若i<j,且Bi和Bj效果是一致的,则删掉Bj(优化2);
    (6) 计算opt[i] = Bi & B(i+1) & B(i+2) … & Bn(可行性剪枝)。
    搜索过程,按照一般的方法做即可,添加最优性剪枝:若当前值大于阶段最剪枝,则跳出;
    添加可行性剪枝,若取剩余所有的Bi也无法达到目标,则剪枝。
  • 代码
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;

long long rest,cover[60],remain[60];

int Size,cnt,ans;
int up[6][6];
bool stick[60];

void initUP()
{
    int i,j;
    for (i = 0;i < Size;i ++) {
        up[i][0] = i*(Size*2+1);
        for(j = 1;j < Size;j ++) {
            up[i][j] = up[i][j-1] + 1;
        }
    }
}

void initCover(int firststick,int sqsize,long long mask)
{
    int i;
    int gap = 2*Size+1;
    int num = firststick;
    for (i = 0;i < sqsize;i ++) {
        cover[num] |= mask;
        cover[num+sqsize*gap] |= mask;
        num ++;
    }
    num = firststick + Size;
    for (i = 0;i < sqsize;i ++) {
        cover[num] |= mask;
        cover[num+sqsize] |= mask;
        num = num + gap;
    }
}

void input()
{
    int i,j,k,n;cin>>Size;
    initUP();
    cin>>cnt;
    memset(stick,true,sizeof(stick));
    for (i = 0;i < cnt;i ++) {
        cin>>n;
        stick[n-1] = false;
    }
    long long mask = 1;
    memset(cover,0,sizeof(cover));
    for (i = 1;i <= Size;i ++) {
        for (j = 0;j <= Size-i;j ++) {
            for (k = 0;k <= Size-i;k ++) {
                initCover(up[j][k],i,mask);
                mask<<=1;
            }
        }
    }
}

void modify()
{
    int i,j,rec;
    rec = Size*(Size+1)*(2*Size+1)/6;
    rest = 1;
    for (i = 1;i < rec;i ++) {
        rest <<= 1;
        rest += 1;
    }
    cnt = 2*Size*(Size+1);
    for (i = 0;i < cnt ;i ++) {
        if (!stick[i]) rest &= ~cover[i];
    }
    for (i = 0;i < cnt;i ++) {
        cover[i] &= rest;
    }
    for (i = 0;i < cnt;i ++) {
        if (!stick[i]) continue;
        else {
            for (j = 0;j < cnt;j ++) {
                if (j != i&&((cover[i]&cover[j]) == cover[j]))
                    stick[j] = false;
            }
        }
    }
    int c = 0;
    for (i = 0;i < cnt;i ++) {
        if (stick[i]) {
            cover[c ++]  = cover[i];
        }
    }
    cnt = c;
    remain[cnt -1 ] = cover[cnt - 1];
    for (i = cnt-2;i >= 0;i --) {
        remain[i] = remain[i+1]|cover[i];
    }
}

void dfs(int c,int last,long long state) 
{
    if (state == rest) {
        ans = c;return;
    } else {
        if (c < ans&&(remain[last+1]|state) == rest) {
            for (int i = last+1;i < cnt;i ++) {
                if ((cover[i]|state)>state) {
                    dfs(c+1,i,state|cover[i]);
                }
            }
        }
    }
}

int main()
{
    int num;
    cin>>num;
    while (num --) {
        input();modify();
        ans = 30;
        dfs(0,-1,0);
        cout<<ans<<endl;
    }
    return 0;
}

http://www.niftyadmin.cn/n/110770.html

相关文章

4.3 where关键字过滤查询数据

文章目录1.使用WHERE子句2.WHERE子句操作符2.1 使用单个值2.2 不匹配检查2.3 范围值查询2.4 空值检查3.组合WHERE子句3.1 AND操作符3.2 OR操作符3.3 计算次序4.IN操作符5.NOt关键字&#xff15;.注意事项&#xff15;.1 NULL与不匹配&#xff15;.2 SQL过滤与应用过滤&#xff…

你知道如何获取全国省市街道区域信息吗?

随着互联网和快递行业的飞速发展&#xff0c;在中国广袤的大地上&#xff0c;全国行政区域规划星罗棋布&#xff0c;要查询一个行政单元如果不运用科技的手段查询可是非常的不易&#xff0c;现在&#xff0c;全国行政区划查询API的作用越来越大&#xff0c;它可以帮助我们对地址…

API接口渗透测试技巧汇总(API安全)

目录 1 API 接口介绍 1.1 RPC(远程过程调用) 1.2 Web Service 1.3 RESTful API 1.4 MVC、MVP、MVVM

企业对不同形态CRM系统价格需求不同

很多企业在选型时关心CRM客户管理系统的价格&#xff0c;有人对CRM的价格完全没有概念&#xff0c;也有的人先问价格再看其他。CRM价格在系统选型中到底有多重要&#xff1f;不同类型CRM系统的价格是否有所不同&#xff1f; CRM的不同产品形态也会影响价格 通常情况下&#x…

圣杯布局的实现方式

1.什么是圣杯布局&#xff1f; 左右盒子固定&#xff0c;中间盒子自适应 2.实现方式 &#xff08;1&#xff09;flex布局 思路&#xff1a;左右盒子给固定的宽高&#xff0c;中间盒子flex:1 <!DOCTYPE html> <html lang"en"> <head> <met…

【代码随想录训练营】【Day28】第七章|回溯算法|93.复原IP地址|78.子集|90.子集II

复原IP地址 题目详细&#xff1a;LeetCode.93 这道题与上一道练习题分割回文字符串十分详细&#xff0c;一样是涉及到分割字符串、判断字符串、递归与回溯的问题&#xff0c;所以这道题要解决的难点在于&#xff1a; 如何分割IP地址字符串如何判断分割的IP地址是否合法递归的…

第三章-OpenCV基础-7-形态学

前置 形态学主要是从图像中提取分量信息&#xff0c;该分量信息通常是图像理解时所使用的最本质的形状特征,对于表达和描绘图像的形状有重要意义。 大体就是通过一系列操作让图像信息中的关键信息更加凸出。同时&#xff0c;形态学的操作都是基于灰度图进行。 相关操作最主要…

CNC数据采集解决方案(2023杭州乐芯科技)

杭州乐芯科技IOT数据采集平台产品是杭州乐芯科技有限公司为满足工业4.0大型集团工厂推出的新一代数据采集平台级产品&#xff0c;可满足单一平台&#xff08;一个服务器&#xff09;同时采集各类设备&#xff0c;同时兼容各种工业数据采集协议&#xff0c;单服务器压力测试达10…