noip 2015 鬥地主 大爆搜
阿新 • • 發佈:2019-02-03
這道題有點坑,如果不是資料水的話,我應該根本活不過來。。。
不過有一個收穫就是,看見大爆搜也不一定要害怕,萬一資料水呢。。。。。。。。。
這道題我做了一下午,當然中間跟hyq下了一次象棋,本來能調的更快的,大概一個半小時之內應該可以。。。。,狀態好的話考場上應該也能拿下!
首先我們明確暴力搜順子,貪心出單牌,我們之所以可以貪心出單牌就是因為資料水,構造資料的話應該能卡掉,我在思考的時候就發現了一些可以卡掉的,資料水沒辦法。。。
先進行搜尋順子,然後從多到少的出單牌;
對於程式碼來說 cnt 是數量為1,2,3,4的 牌的數量。。。
而card是每一種牌的數量。。
#include<iostream> #include<algorithm> #include<string> #include<cmath> #include<queue> #include<cstring> using namespace std; int t,n; int card[20],tmp[20],cnt[20],l; int ans; void init(){ ans=n; memset(card,0,sizeof(card)); memset(tmp,0,sizeof(tmp)); } int sanpai(){ memset(tmp,0,sizeof(tmp)); int res=0; l=0; for(int i=1;i<=14;i++) tmp[i]=card[i],cnt[card[i]]++; for(int i=1;i<=14;i++){ if(card[i]){ l=i; break; } if(l==14) return 1; } if(cnt[4]&&cnt[2]>=2){ for(int i=l;i<=13;i++){ int vis=0; if(tmp[i]==4){ for(int j=l;j<=14;j++){ if(tmp[j]!=2||vis) continue; for(int k=l;k<=14;k++){ if(tmp[k]!=2||k==j||vis) continue; cnt[4]--; cnt[2]-=2; tmp[i]-=4,tmp[j]-=2,tmp[k]-=2; vis=1; res++; } } } } } if(cnt[4]&&cnt[1]>=2){ for(int i=l;i<=13;i++){ int vis=0; if(tmp[i]==4){ for(int j=l;j<=14;j++){ if(tmp[j]!=1||vis) continue; for(int k=l;k<=14;k++){ if(tmp[k]!=1||k==j||vis) continue; cnt[4]--; cnt[1]-=2; tmp[i]-=4,tmp[j]-=1,tmp[k]-=1; vis=1; res++; } } } } } if(cnt[4]&&(cnt[1]==1)&&(cnt[2]==1||cnt[3]==1)){ for(int i=l;i<=13;i++){ int vis=0; if(tmp[i]==4){ for(int j=l;j<=14;j++){ if(tmp[j]!=1||vis) continue; for(int k=l;k<=14;k++){ if(tmp[k]<=1||k==i||k==j||vis) continue; cnt[4]--; cnt[1]-=1; if(tmp[k]==2) cnt[2]-=1,tmp[k]-=1,cnt[1]+=1; if(tmp[k]==3) cnt[3]-=1,tmp[k]-=1,cnt[2]+=1; tmp[i]-=4,tmp[j]-=1; vis=1; res++; } } } } } if(cnt[3]&&cnt[2]){ for(int i=l;i<=13;i++){ int vis=0; if(tmp[i]==3){ for(int j=l;j<=14;j++){ if(tmp[j]!=2||vis) continue; cnt[3]--;cnt[2]--; tmp[i]-=3,tmp[j]-=2; vis=1; res++; } } } } if(cnt[3]&&cnt[1]){ for(int i=l;i<=13;i++){ int vis=0; if(tmp[i]==3){ for(int j=l;j<=14;j++){ if(tmp[j]!=1||vis) continue; cnt[3]--;cnt[1]--; tmp[i]-=3,tmp[j]-=1; vis=1; res++; } } } } for(int i=l;i<=14;i++){ if(tmp[i]) res++; } return res; } void dfs(int dep){ if(dep>ans) return; int tmp=sanpai(); if(tmp+dep<ans) ans=tmp+dep; for(int i=1;i<=14;i++){ if(card[i]){ l=i; break; } if(l==14){ ans=dep; return; } } memset(cnt,0,sizeof(cnt)); for(int i=1;i<=14;i++) cnt[card[i]]++; if(cnt[3]+cnt[4]>=2){ for(int i=l;i<=12;i++){ for(int j=i+1;j<=12;j++){ int liang=0; for(int k=i;k<=j;k++){ if(card[k]<3){ liang=1;break; } } if(!liang){ for(int k=i;k<=j;k++){ card[k]-=3; if(card[k]){ cnt[4]--; cnt[1]++; } else cnt[3]--; } dfs(dep+1); for(int k=i;k<=j;k++){ if(card[k]){ card[k]+=3; cnt[1]--; cnt[4]++; } else{ card[k]+=3; cnt[3]++; } } } } } } if(cnt[2]+cnt[3]+cnt[4]>=3){ for(int i=l;i<=12;i++){ for(int j=i+2;j<=12;j++){ int liang=0; for(int k=i;k<=j;k++){ if(card[k]<2){ liang=1;break; } } if(!liang){ for(int k=i;k<=j;k++){ card[k]-=2; if(card[k]==1){ cnt[3]--; cnt[1]++; } if(card[k]==2){ cnt[4]--; cnt[2]++; } if(card[k]==0){ cnt[2]--; } } dfs(dep+1); for(int k=i;k<=j;k++){ if(card[k]==1){ cnt[3]++; cnt[1]--; } if(card[k]==2){ cnt[4]++; cnt[2]--; } if(card[k]==0){ cnt[2]++; } card[k]+=2; } } } } } if(cnt[1]+cnt[2]+cnt[3]+cnt[4]>=5){ for(int i=l;i<=12;i++){ for(int j=i+4;j<=12;j++){ int liang=0; for(int k=i;k<=j;k++){ if(card[k]<1){ liang=1;break; } } if(!liang){ for(int k=i;k<=j;k++){ card[k]-=1; if(card[k]==1){ cnt[2]--; cnt[1]++; } if(card[k]==2){ cnt[3]--; cnt[2]++; } if(card[k]==0){ cnt[1]--; } if(card[k]==3){ cnt[4]--; cnt[3]++; } } dfs(dep+1); for(int k=i;k<=j;k++){ if(card[k]==1){ cnt[2]++; cnt[1]--; } if(card[k]==2){ cnt[3]++; cnt[2]--; } if(card[k]==0){ cnt[1]++; } if(card[k]==3){ cnt[4]++; cnt[3]--; } card[k]+=1; } } } } } } int main(){ cin>>t>>n; while(t--){ init(); for(int i=1;i<=n;i++){ int d,t; cin>>d>>t; if(d>=3&&d<=13) card[d-2]++; if(d==0) card[14]++; if(d==2) card[13]++; if(d==1) card[12]++; } dfs(0); cout<<ans<<endl; } }