Luogu P2915 [USACO08NOV]奶牛混合起來

題外話:c++

是很是頹廢的博主spa

寫題解也不在於能不能經過啦,主要是緩解頹廢code

首先看到這個題,確定是能夠暴力搜索的:get

不得不說這道題仍是很善良的,一波大暴力dfs,竟然有70pts:it

#include<bits/stdc++.h>

using namespace std;

inline int read() {
    int ans=0;
    char last=' ',ch=getchar();
    while(ch>'9'||ch<'0') last=ch,ch=getchar();
    while(ch>='0'&&ch<='9') ans=(ans<<1)+(ans<<3)+ch-'0',ch=getchar();
    if(last=='-') ans=-ans;
    return ans;
}

int n,k;
int s[20];
long long ans;
bool vis[20];
void dfs(int cnt,int nxt) {
    if(cnt==n) {
        ans++;
        return;
    }
    for(int i=1;i<=n;i++) {
        if(vis[i]) continue;
        if(abs(s[i]-nxt)>k) {
            vis[i]=1;
            dfs(cnt+1,s[i]);
            vis[i]=0;
        }
    }

}

int main() {
    n=read();
    k=read();
    for(int i=1;i<=n;i++) 
        s[i]=read();
    dfs(0,-k-1);
    printf("%lld",ans);
    return 0;
}

想改記憶化,而後我發現我不會ast

滾回來從新考慮dp:class

將奶牛狀壓到一個二進制數中,第i位表示這頭奶牛是否在隊伍中;(突兀搜索

咱們設 \(dp[i][j]\) 表示當前狀態爲i,最後一個加入隊伍的奶牛是j的方案數;二進制

考慮如何轉移:im

設如今的狀態爲 \(dp[i][j]\)

考慮枚舉下一個加入隊伍的奶牛g是哪一隻,那麼首先確定要知足的,就是這隻奶牛不能已經加入隊伍了 (奶牛:我有分身術 也就是i&(1<<(g-1))==0

1.若是已經在隊伍裏,顯然要continue;(廢話

2.若是不在隊伍裏,那麼判斷第g頭奶牛和第j頭奶牛之間的編號之差是否>k,一樣的不是就continue掉 (一樣的廢話

若是上面兩個條件都知足,那麼就能夠將g加入隊伍,對應的狀態 \(dp[i|(1<<(g-1))][g]+=dp[i][j];\)

考慮初始化:

對於只有一頭奶牛的狀況,顯然只有一種方案,所以 \(dp[1<<(i-1)][i]=1;\)

而後由於上面講的 很是很是之亂,我們來理一理思路:
首先顯然是初始化,將只有一頭奶牛的方案的值初始化爲1

接下來枚舉每一種狀態

第二維枚舉當前狀態下,最後一個加入隊伍的奶牛j是哪一隻(能夠直接從1~n枚舉,用i&(1<<(j-1))!=0來判斷合法與否

而後枚舉下一頭加入隊伍的奶牛是哪一頭,判斷是否符合上面的兩個條件,相應的進行修改

最後顯然是輸出答案啦:顯然最後的答案應該是全部奶牛都加入了隊伍,每一頭奶牛最後進入隊伍的方案數相加,也就是 \(\sum\limits_{i=1}^n dp[(1<<n)-1][i]\)

而後,大概應該可能就能夠愉快的AC了?(是 碼風清奇的奇女子,將就着看吧

#include<bits/stdc++.h>

using namespace std;

inline int read() {
    int ans=0;
    char last=' ',ch=getchar();
    while(ch>'9'||ch<'0') last=ch,ch=getchar();
    while(ch>='0'&&ch<='9') ans=(ans<<1)+(ans<<3)+ch-'0',ch=getchar();
    if(last=='-') ans=-ans;
    return ans;
}

int n,k;
int s[20];
long long ans;
long long dp[70000][18];

int main() {
    n=read();
    k=read();
    for(int i=1;i<=n;i++) 
        s[i]=read();
    for(int i=1;i<=n;i++)
        dp[1<<(i-1)][i]=1;
    for(int a=1;a<(1<<n);a++) {
        for(int j=1;j<=n;j++) {
            if(!(a&(1<<(j-1)))) 
                continue;
            for(int g=1;g<=n;g++) {
                if((a&(1<<(g-1)))) 
                    continue;
                if(abs(s[j]-s[g])<=k) 
                    continue;
                dp[a|(1<<(g-1))][g]+=dp[a][j]; 
            }
        }
    }
    for(int i=1;i<=n;i++) 
        ans+=dp[(1<<n)-1][i];
    printf("%lld\n",ans);
    return 0;
}

//一堆括號看的我眼疼

相關文章
相關標籤/搜索