類狀壓之搜城探寶
阿新 • • 發佈:2020-07-04
題目
思路
看到資料在20以內,果斷跑狀壓,但是由於我太弱了,最後沒有調過來,然後在狀壓的基礎上,做了這道題,
按照狀壓的思路,首先列舉狀態,根據題目要求篩去不合法的情況
判斷合法的函式(judge)內容
- if(Q(x)!=(k+1))return 0,代表,在房間數大於法寶數的情況下,如果法寶沒有全部用完,其所得到的價值絕對沒有法寶全部用完得到的價值高,如果用的法寶數大於(k+1)(包括鑰匙和傳送們),那麼絕對不合法
- 用num記錄傳送們的使用次數,列舉每一個點,判斷其父節點是否出現過,
if((!((1<<(fa[i]-1))&x)) && ((1<<(i-1))&x))num++;
如果一個節點在該狀態下,但是其父節點不在其中,則到達該節點時使用了傳送們,如果num>1即為不合法
- 在篩選後,對剩下的狀態求解最大價值即可
附上程式碼,玄學時間效率
#include<bits/stdc++.h> using namespace std; const int maxn=1<<20+1; int f[25][maxn]; int n,k; int fa[25],w[25]; int lo[maxn],ans[maxn]; int tot=0; int lowbit(int x){ return x&-x; } int Q(int x){ int cnt=0; while(x){ x-=lowbit(x); cnt++; } return cnt; } bool judge(int x){ if(Q(x)!=(k+1))return 0; int num=0; for(int i=2;i<=n;i++){ if((!((1<<(fa[i]-1))&x)) && ((1<<(i-1))&x)){ num++; if(num>1){ return 0; } } } return 1; } int main(){ scanf("%d%d",&n,&k); int x,y; for(int i=1;i<n;i++){ scanf("%d%d",&x,&y); fa[y]=x; } int sum=0; for(int i=1;i<=n;i++){ scanf("%d",&w[i]); sum+=w[i]; } if(k+1>=n){ printf("%d\n",sum); return 0; } int lim=1<<n; for(int i=0;i<lim;i++){ if(judge(i)){ lo[++tot]=i; } } int Max=0; for(int i=1;i<=tot;i++){ for(int j=1;j<=n;j++){ if(lo[i]&(1<<(j-1))){ ans[i]+=w[j]; } } Max=max(Max,ans[i]); } printf("%d\n",Max); }