DS集训练习题第一天(2020/12/28)——题解

1.由于是北大OJ所以代码部分万能头文件不能用,整体思路就是按行枚举,找到‘#’同时判断对应行列标记数组是否已经被标记,本题唯一的坑在于,按行遍历的起始行需要在上一层的行数基础上+1枚举下一行,否则会导致后面的与前面重复配对,而且你还没来得及WA就TLE了。http://poj.org/problem?id=1321

#include<iostream>
#include<stdio.h>
using namespace std;
char a[9][9];
int col[9]={0};
int n,k;
int sum=0;
void dfs(int u,int x)
{
    if(u==k)
    {
        sum++;
        return;
    }
    else
    {
        for(int i=x;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(a[i][j]=='#'&&!col[j])
                {
                    col[j]=1;
                    dfs(u+1,i+1);
                    col[j]=0;
                }
            }
        }
    }

}
int main()
{
    while(1)
    {
        scanf("%d%d",&n,&k);
        if(n==-1&&k==-1)
        {
            break;
        }
        else
        {
            for(int i=0;i<n;i++)
            {
                for(int j=0;j<n;j++)
                {
                    cin>>a[i][j];
                }
            }
        }
        dfs(0,0);
        printf("%d\n",sum);
        sum=0;
    }
    return 0;
}

2.暴力枚举+氧气优化(不优化TLE),和dfs没什么关系。https://www.luogu.com.cn/problem/P2105

#include<iostream>
#include<stdio.h>
#include<bits/stdc++.h>
#define N 20020
using namespace std;
int n,m,K;
int sum;
int a[N],b[N],c[N*2],d[N*2];
int main()
{
    scanf("%d%d%d",&n,&m,&K);
    for(int i=1;i<=K;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        a[x]=1;
        b[y]=1;
        c[x+y]=1;
        d[x-y+N]=1;
    }
    for(int i=1;i<=n;i++)
    {
        if(a[i]) continue;
            for(int j=1;j<=m;j++)
            {
                if(!a[i]&&!b[j]&&!c[i+j]&&!d[i-j+N])
                {
                    sum++;
                }
            }
    }
    printf("%d\n",sum);
    return 0;
}
  1. 下面的(x,y)相当于(u,i)
    (1)反对角线 y=x+b,截距b=y−x,因为我们要把b当做数组下标,所以 bb 不能是负的,所以我们 +n,保证是结果是正的
    (2)而对角线 y=−x+b,截距是 b=y+x这里截距一定是正的,所以不需要加偏移量
    核心目的:找一些合法的下标来表示dg或udg是否被标记过,所以如果你愿意,你取 udg[n+n−u+i]也可以,只要所有(u,i)对可以映射过去就行。
    https://www.luogu.com.cn/problem/P1219

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 30;
    // bool数组用来判断搜索的下一个位置是否可行
    // col列,dg对角线,udg反对角线
    // g[N][N]用来存路径
    int n;
    int g[N];
    bool col[N], dg[N], udg[N];
    int sum=0;
    void dfs(int u)
    {
     // u == n 表示已经搜了n行,故输出这条路径
     if (u == n)
     {
         if(sum<3)
         {
             for (int i = 0; i < n; i ++ ) printf("%d ",g[i]);   // 等价于cout << g[i] << endl;
             puts("");  // 换行       
         }
         sum++;
         return;
     }
    
     //对n个位置按行搜索
     for (int i = 0; i < n; i ++ )
         // 剪枝(对于不满足要求的点,不再继续往下搜索)              udg[n - u + i],+n是为了保证大于0
         if (!col[i] && !dg[u + i] && !udg[n - u + i])
         {
             g[u]=i+1;
             col[i] = dg[u + i] = udg[n - u + i] = true;
             dfs(u + 1);
             // 恢复现场 这步很关键
             col[i] = dg[u + i] = udg[n - u + i] = false;
         }
    }
    int main()
    {
     cin >> n;
     dfs(0);
     printf("%d\n",sum);
     return 0;
    }   
全部评论

相关推荐

感觉他们一点都不了解现在这个社会就业有多难,已经在牛客刷到好多篇&nbsp;延毕的帖子了,延毕就会导致已经找好的工作就没了,还得重新再找,学校和老师们是怎么想的呢????看到学生丢失工作会开心吗&nbsp;就业数据都在造假,真实的就业困难不去解决&nbsp;一个个真是好样的
从今天开始狠狠卷JVAV_癫:学生看到的是导师不放实习导致offer黄了。 导师看到的是招进来的学生吃自己补助和自己的招生名额,却没给自己升迁带来任何帮助,还要跑路。 根本利益的不一致,最主要留校的导师大概率是职场上招聘失败的,被迫留校的,什么牛鬼蛇神都会有
点赞 评论 收藏
分享
05-26 22:25
门头沟学院 Java
Java小肖:不会是想叫你过去把你打一顿吧,哈哈哈
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务