1. 程式人生 > >noip 2015 鬥地主 大爆搜

noip 2015 鬥地主 大爆搜

這道題有點坑,如果不是資料水的話,我應該根本活不過來。。。

不過有一個收穫就是,看見大爆搜也不一定要害怕,萬一資料水呢。。。。。。。。。

這道題我做了一下午,當然中間跟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;
	} 
	
}