計蒜客藍橋杯模擬賽五J 程式設計 放置守衛

2022-05-23 01:45:12 字數 3102 閱讀 8244

在一張n行

m列的方格地圖上放置一些守衛,每個守衛能守護上、左、右三個方向上相鄰的方格和自己所在的方格。如下圖,紅色的方格放置守衛,綠色的方格為該守衛守護的區域。

現在要求在地圖上放置若干個守衛,讓每個方格至少被乙個守衛守護(可以同時被多個守衛守護),但是有些方格上不能放置守衛(這個方格也需要被守護),求出最少需要多少個守衛才能滿足條件。

第一行輸入兩個整數

n, m

。接下來輸入乙個

n×m的矩陣。矩陣中元素為 0 表示該位置不能放置守衛,為 1 表示該位置能放置守衛。元素之間用空格隔開。

資料約定:

所有資料保證一定有一種方案滿足條件。

對於 20% 的資料: 1≤n,m≤5;

對於 50% 的資料: 1≤n≤20,1≤m≤10;

對於100% 的資料: 1≤n∗m≤1000,1≤m≤15。

輸出最少需要放置的守衛數量。

沒有打這個。。不過學校群有人發出來了。做了下,沒得交,大概思路應該是對的

做法:

我們做乙個dp,假設格仔移動到了圖中標記為1的地方,我們定義dp[now][sta]為當移動到這個格仔,而且(4,3,2,1,0)的狀態為sta的二進位制表示(順序也是一樣的,1表示已放置,0表示未放置),並且這個分界線以上的全部被放置了的最小放置守衛數,這個分界線是這樣的,當轉移到(i,j)時,分界線就是(i,0)(i,1)...(i,j)(i-1,j)(i-1,j+1)..(i-1,m-1)轉移比較簡單,初始化第乙個格仔的時候,我們知道第乙個格仔是沒有格仔的,但是我們把那裡當成已被守衛的格仔就好了所以就是dp[now][(1 << m+1) - 2] = 0,其他定義為-1。

舉個例子吧,下面的數字外面一層表示行列數,裡面的表示分界線

0 1 2 3

0  _ _ 3 4

1  0 1 2 _

圖1我們知道我們當前是轉移到(1,2)這個位置的,當這個位置可以放守衛,我們選擇放乙個守衛之後

0 1 2 3

0  _ _ _ 4

1  0 1 2 3

圖2現在轉移到下乙個格仔了,但是剛剛在(1,2)放了守衛,所以(1,1)(1,2)(1,3)(0,2)這四個位置的狀態都要變成了1,所以我們的sta需要或乙個(1 << (j-1))(1 << (j))(1 << (j+1))如果j-1小於0就不用了,(0,2)這個位置已經到了分界線外。所以如果當前格仔上面是沒有守衛的,就必須放乙個。因為我們定義的dp是分界線上必須全部被守衛。

如果當前格仔有守衛,我們可以選擇不放,如果不放的話我們需要把sta^(1 << (j + 1)),因為我們可以知道圖1的分界線3轉移到下乙個的圖2時,這個位置原本是沒有守衛的,所以要置為0。

這上面的轉移是一種情況,但是當轉移需要換行的時候,轉移的式子會有所改變,不過手推很容易推出來。

#include #include 

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using

namespace

std;

#define mp make_pair

#define rep(i,n) for(int i = 0; i < (n); i++)

#define per(i,n) for(int i = (n-1); i >= 0; i--)

#define rep1(i,n) for(int i = 1; i <= (n); i++)

#define per1(i,n) for(int i = (n); i > 0; i--)

#define pb push_back

#define mst(a,b) memset((a),(b),sizeof(a))typedef

long

long

ll;typedef unsigned

long

long

ull;

typedef pair

pii;

typedef vector

vi;typedef vector

vii;

const

int inf = 0x3f3f3f3f

;const ll inf = (1ull << 63) - 1

;const ll mod = 1000000007

;const

int n = 1e5 + 7

;const

double pi = acos(-1.0

);const

int maxn = (1

<< 16) + 7

;const ull hashmod = 29050993

;int dp[2

][maxn];

int maz[1005][15

];int

n, m;

inline

bool up(int sta, int

pos)

inline

void umin(int &a, int

b) inline

int set(int sta, int

pos)

return

sta;

}inline

int noset(int sta,int

pos)

//inline void show(int x)

intmain() }}

}int ans = dp[now][(1

<< (m + 1)) - 1

]; umin(ans,dp[nx][(

1<< (m + 1)) - 2

]); cout

<< ans <

}

view code

計蒜客藍橋杯省賽模擬五

a.了解進製轉換原理 b.熟練掌握求數字中各個位置數的方法 includeusing namespace std int check int a return re int main void printf lld n ans return 0 c.做法一 費馬小定理的運用,若a和b互質,則a的 b...

計蒜客藍橋杯模擬賽心得

1.有趣的數字 我們稱乙個數是質數,而且數字 現了 55 的數字是有趣的。例如 5,59,457 都是有趣的,而 15,7 不是。求 1 到 100000 中有趣的數的個數。思路 其實很簡單,1 判斷是否為素數 2 位數是否含有5 注意點 剛開始以為要總數減去1,就是15這個數,後來才發現15不是素...

2019計蒜客藍橋杯模擬賽三

思路 一開始遞推推錯了,改用dfs includeusing namespace std int ans void dfs int x,int sum 記住i從x開始搜的這一剪枝,不僅僅可以提公升效率 更重要的是可以保證搜尋出來的結果不會重複,是有序的 for int i x i 10 sum i ...