[UVA11825]Hackers' Crackdown(狀壓dp)
阿新 • • 發佈:2019-01-10
題解降智警告
吐槽降智警告
思路降智警告
程式碼降智警告
題目傳送門 洛谷
果然水題做多了連半道難點的都能給咱幹蒙...
水題做多了降智 --魯迅
題目大意:見傳送門
心路歷程見末尾
正解(大概):
狀壓
雖然有些難以理解,但是這道題裡面有兩種集合
一種是第i臺電腦所聯通的合起來就是S[i](程式碼內的line[i])
另一種是指已經用了哪幾臺電腦
思路開始
反正無論如何一定得用幾個S[i]拼成一個全集(1<<n)-1
於是就有了
1 struct Union好孩子不要急著就看哦(大霧)2 { 3 int A; 4 }U[1<<16];//可以湊出來一個全集的幾個電腦的集合 5 int Uarr; 6 void getU(int st,int A,int p) 7 { 8 if(st==((1<<n)-1))//這幾個電腦的line集合拼成了全集 9 { 10 U[Uarr].A=A; 11 Uarr++; 12 return; 13 } 14 if(p>=n) return; 15 getU(st|line[p],A|(1<<p),p+1);//集合里加這個電腦 16 getU(st,A,p+1);//不加 17 }
(寫法比較樸素的說)
好了我們的重點部分已經完事了
(啥你這就完事了?)
確實想到這個就好寫了...
如果你做過[NOIP2016]憤怒的小鳥
那這題就更好想到了
好了上程式碼
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using std::sort; 5 int max(int好孩子要自己思考~a,int b){return a>b?a:b;} 6 int n,m; 7 8 int dp[1<<16]; 9 int line[16]; 10 11 struct sta 12 { 13 int s,sc; 14 }s[1<<16]; 15 int sarr; 16 void getsta(int st,int sc,int p) 17 { 18 if(p>=n) 19 { 20 s[sarr].s=st; 21 s[sarr].sc=sc; 22 sarr++; 23 return; 24 } 25 getsta(st|(1<<p),sc+1,p+1); 26 getsta(st,sc,p+1); 27 } 28 29 struct Union 30 { 31 int A; 32 }U[1<<16]; 33 int Uarr; 34 void getU(int st,int A,int p) 35 { 36 if(st==((1<<n)-1)) 37 { 38 U[Uarr].A=A; 39 Uarr++; 40 return; 41 } 42 if(p>=n) return; 43 getU(st|line[p],A|(1<<p),p+1); 44 getU(st,A,p+1); 45 } 46 47 bool cmp(sta a,sta b)//狀態按照1的數量排序(咱就好這一手) 48 { 49 if(a.sc==b.sc) return a.s<b.s; 50 else return a.sc<b.sc; 51 } 52 53 void memclr() 54 { 55 memset(line,0,sizeof(line)); 56 memset(dp,0,sizeof(dp)); 57 Uarr=0; 58 sarr=0; 59 } 60 int main() 61 { 62 int xin,kk=0; 63 while(scanf("%d",&n)!=EOF) 64 { 65 if(n==0) return 0; 66 memclr(); 67 getsta(0,0,0); 68 sort(s,s+sarr,cmp); 69 for(int i=0;i<n;i++) 70 { 71 scanf("%d",&m); 72 line[i]|=(1<<i); 73 for(int j=1;j<=m;j++) 74 { 75 scanf("%d",&xin); 76 line[i]|=(1<<xin); 77 } 78 } 79 getU(0,0,0); 80 for(int si=0;si<sarr;si++) 81 { 82 for(int Ui=0;Ui<Uarr;Ui++) 83 { 84 if((s[si].s&U[Ui].A)==U[Ui].A) 85 { 86 dp[s[si].s]=max(dp[s[si].s],dp[s[si].s^U[Ui].A]+1); 87 } 88 } 89 } 90 printf("Case %d: %d\n",++kk,dp[(1<<n)-1]); 91 } 92 return 0; 93 }
看上去做的十分輕鬆
實際上
心路歷程如下:
一開始:emmmm外層電腦使用狀態裡面列舉下一個使用每個電腦然後dp裡存v和狀態...
寫完:???
等下等下從下面能繼承過來一堆狀態啊啊啊
變成(2^n)^k了啊啊啊啊啊
心態爆炸
Ah~(油庫裡音)
切題後:
啥?子集的子集是3^n?
完了我菜死了
陷入沉思...
3^n*n似乎也會T死
這至少證明了我原先的思路似乎沒啥可行性而不是半途而廢(什麼邏輯)
心態平衡了
Ah~(油庫裡音)
以上
本題完結
記住
水題做多了降智
我沒說過這句話 --魯迅