1. 程式人生 > >NOIP2018提高組省一衝獎班模測訓練(一)

NOIP2018提高組省一衝獎班模測訓練(一)

比賽連結

https://www.51nod.com/contest/problemList.html#!contestId=72&randomCode=147206

這次考試的題非常有質量

這次考試暴露了非常多的問題,心理給自己設限,知識點不熟練等等問題。

只拿了暴力的分。

 

奈芙蓮的護符

這道題複習狀壓dp,狀壓dp一般可以處理一個集合內的問題

這道題是第三題,但我放在這一題

因為這一題反而最水……

我當時一看到資料範圍20,馬上想到狀壓dp

但是一方面因為覺得這是第三題,應該會比較難,而且前面兩道題都做不出來,所以心理障礙

很大,就沒有怎麼很深入的去想(不過說到底還是狀壓dp不熟練

)。

考完後,5分鐘秒了,發現這是我做過最水的狀壓dp題。

這道題和TSP問題很類似(不懂的可以百度一下,或者我部落格裡面有)

用1表示魔力還在,0表示沒有了。

那麼dp[S] = min(dp[S], dp[S^(1<<j)] + c[j][i])

#include<bits/stdc++.h>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using
namespace std; const int MAXM = (1 << 20) + 10; const int MAXN = 30; int c[MAXN][MAXN], dp[MAXM]; int num(int x) { return !x ? 0 : 1 + num(x & (x - 1)); } //二進位制中1的個數 int main() { int n, k; scanf("%d%d", &n, &k); REP(i, 0, n) REP(j, 0, n) scanf(
"%d", &c[i][j]); int ans = 1e9; memset(dp, 0x3f, sizeof(dp)); //這裡初始化要注意 dp[(1<<n)-1] = 0; for(register int S = (1 << n) - 1; S >= 0; S--) { if(num(S) < k) continue; REP(i, 0, n) if(S & (1 << i)) REP(j, 0, n) if(!(S & (1 << j))) dp[S] = min(dp[S], dp[S^(1<<j)] + c[j][i]); if(num(S) == k) ans = min(ans, dp[S]); } printf("%d\n", ans); return 0; }

 

奈芙蓮的序列

這是第二題。我覺得第一題才是最難的,最後講