1. 程式人生 > >日照學習提高班day3測試 x

日照學習提高班day3測試 x

clu 分答 div 9.png style 技術 數組 har 一次

技術分享

技術分享

技術分享

技術分享

思路:

  一看到‘#‘‘.‘什麽的就想到搜索怪我怪我。。。

  這道題勉強說是搜索別打我qwq

  1)因為不重復,所以首先要判斷是否%5==0,若不滿足,直接輸出NO

  2)弄個vis數組記錄是否被搜過,如果該處是‘#’並且沒有被搜索過,就搜索他正下,左下,右下,以及下下是否都為#,若不是,輸出NO

  3)如果是就進行標記(5個點都進行標記,因為只能使用一次),最終如果成功的渡劫,輸出YES

坑點:

  搜索下方是x+1而不是x-1(吃虧了qwq)

上代碼:

#include <algorithm>
#include 
<iostream> #include <cstring> #include <cstdio> #include <cmath> using namespace std; int n,cnt,tot; char w[110][110]; bool vis[110][110]; int dx[4] = {0, 0,1,-1}, dy[4] = {1,-1,0, 0}; bool check(int x,int y) { if(x>n || x<1 || y>n || y<1 || vis[x][y])
return false; return true; } void dfs(int x,int y) { for(int i=0;i<4;++i) { int xx=x+dx[i],yy=y+dy[i]; if(!check(xx,yy)) continue; if(w[xx][yy]==#) tot++; } } void dfs2(int x,int y) { for(int i=0;i<4;++i) {
int xx=x+dx[i],yy=y+dy[i]; vis[xx][yy]=true; } } bool orz(int x,int y) { vis[x+1][y]=true; tot=0; dfs(x+1,y); if(tot==4) { dfs2(x+1,y); return true; } return false; } int main() { freopen("puzzle.in","r",stdin); freopen("puzzle.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;++i) { scanf("%s",w[i]+1); for(int j=1;j<=n;++j) if(w[i][j]==#) ++cnt; } if(cnt%5) { printf("NO"); return 0; } else if(!cnt) { printf("YES"); return 0; } for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) if(w[i][j]==# && !vis[i][j]) { if(!orz(i,j)) { printf("NO"); return 0; } } printf("YES"); return 0; }


技術分享

技術分享

技術分享

思路:

  題目大整容!!!

  luoguP2816宋榮子搭積木

  貪心。

  1)先將所有的盒子按照承載量從小到大排序

  2)然後我們開一個數組,記錄一下當前一共有多少列,每一列一共有多少個盒子。

  3)接著從小到大掃描所有的盒子,找到能放下的數量最多的列,把它放進去。

  4)如果沒有任何一列能放下,則建一個新列。

上代碼:

#include <algorithm>
#include <iostream>
#include <cstdio>
using namespace std;

const int Maxn = 5e3 + 233;
int n,tot;
int a[Maxn],b[Maxn];

inline void works()
{
    for(int i=1;i<=n;++i)
        if(!tot)///創造新列
            b[++tot]=1;
        else {///Maxx用來記錄上面放了多少塊積木
            int Maxx=0,flag=0;
            for(int j=1;j<=tot;++j)
                if(a[i]>=b[j] && b[j]>Maxx)
                    Maxx=b[j],flag=j;
            if(!flag)///若積木不高興了
                b[++tot]=1;///再建一個列
            else///裝入該列
                b[flag]++;
        }
    cout<<tot;
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
        scanf("%d",&a[i]);
    sort(a+1,a+1+n);///記住一定要進行排序!!畢竟貪心嘛,,,
    works();
    return 0;
}


技術分享

技術分享

技術分享

思路:

  題目大整容!

  luoguP1525關押罪犯

  三種做法

  1)普通並查集:

     i表示第i個學生,i+n為虛擬節點,表示不能和i在一個宿舍的人

    若兩個點在同一並查集中,說明它們必須被分到同一個宿舍樓

    然後將所有的愛慕關系從大到小排序

    若a和b在同一並查集中,則此時c為答案

    若不在同一並查集,令a與b+n所在並查集合並,b與a+n所在並查集合並

  2)加權並查集:

    同樣將所有愛慕關系從大到小排序

    每個點存儲額外信息type,type為0表示和父親結點在同一個宿舍樓,1表示和父親結點不在同一個宿舍樓

    合並與查詢的方式類似食物鏈

  3)二分+dfs:

    二分答案

    對於比二分答案大的愛慕關系,建圖,

    顯然若該圖可以黑白染色,該答案可行,反之不可行

上代碼:

給出普通並查集做法哦~

#include <algorithm>
#include <iostream>
#include <cstdio>
using namespace std;

int n,m,dad[40010];

struct node {
    int a,b,c;
    bool operator < (const node &qwq)const
    {///重載運算符 
        return c > qwq.c;
    }
}e[100010];

int getdad(int x)
{return x == dad[x] ? x : dad[x]=getdad(dad[x]);}

int main()
{
    freopen("love.in","r",stdin);
    freopen("love.out","w",stdout);
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n*2;i++)
        dad[i]=i;///構建虛擬點 
    for(int i=1;i<=m;i++)
       scanf("%d %d %d",&e[i].a,&e[i].b,&e[i].c);
    sort(e+1,e+1+m);
    for(int i=1;i<=m;i++)
    {
        int f1=getdad(e[i].a),f2=getdad(e[i].b);
        if(f1==f2)
        {
            printf("%d",e[i].c);
            return 0;
        }
        ///與虛擬點進行合並,表示不再一個宿舍中 
        dad[f1]=getdad(e[i].b+n);///將f1與 b的補集合並
        dad[f2]=getdad(e[i].a+n);///將f2與 a的補集合並
    }
    ///若合法: 
    printf("0");
    return 0;
}

日照學習提高班day3測試 x