zoukankan      html  css  js  c++  java
  • 【NOIP2015】斗地主(dfs)

    练练码力。
    如果没有顺子,显然最小出牌次数可以贪心,优先出四带二,然后三带一或三带二,最后出对拍和单牌。
    把大小王归到单排一类中,最后特判如果剩余的单排大于2,把这两张当成大小王一起出。
    枚举所有出顺子的情况,用三个dfs,其中:

    dfs(int now, int l, int tot, int times)
    //now 当前到了第几小的牌
    //l 当前顺子的长度
    //tot 当前已经出了几次牌
    //times 当前大小的顺子(三顺,二顺,单顺)重复搜索了几遍
    

    关于为什么要用用times记录并重复搜索:
    考虑这组牌

    [egin{aligned} 3quad4quad5quad6quad6quad7quad7quad8quad9quad10 end{aligned} ]

    显然答案为两次,分别是3到7,6到10,中间有重复的部分,所以需要重复搜索。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <vector>
    #include <queue>
    using namespace std;
    const int N = 30;
    const int h[] = {14, 12, 13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
    int n, ans = 1e9;
    int card[N];
    bool flag = false;
    void check(int tt) {
    	int t[5]; memset(t, 0, sizeof(t));
    	for(int i = 1; i <= 15; i++) {
    		t[card[i]]++;
    	}
    	while(t[4]) {
    		if(t[1] >= 2) {
    			t[4]--; t[1] -= 2; tt++; continue;
    		}	else if(t[2] >= 2) {
    			t[4]--; t[2] -= 2; tt++; continue;
    		} else if(t[2] >= 1) {
    			t[4]--; t[2]--; tt++; continue;
    		} else {
    			t[4]--; tt++; continue;
    		}
    	}
    	while(t[3]) {
    		if(t[1] >= 1) {
    			t[3]--; t[1]--; tt++; continue;
    		} else if(t[2] >= 1) {
    			t[3]--; t[2]--; tt++; continue;
    		} else {
    			t[3]--; tt++; continue;
    		}
    	}
    	while(t[2]) tt++, t[2]--;
    	if(flag && t[1] >= 2) {
    		t[1] -= 2; tt++;
    	}
    	tt += t[1];
    	ans = min(ans, tt);
    	return ;
    }
    void dfs2(int now, int l, int tot, int times) {
    	if(now == 13) {
    		if(l >= 5) {
    			if(times < 4) dfs2(1, 0, tot + 1, times + 1);
    			if(times == 4) check(tot + 1);
    		}
    		else if(l == 0) {
    			if(times < 4) dfs2(1, 0, tot, times + 1);
    			if(times == 4) check(tot);
    		}
    		return ;
    	}
    	if(card[now] >= 1) {
    		card[now] -= 1;
    		dfs2(now + 1, l + 1, tot, times);
    		card[now] += 1;
    		if(l >= 5) dfs2(now + 1, 0, tot + 1, times);
    	} else {
    		if(l >= 5) dfs2(now + 1, 0, tot + 1, times);
    	}
    	if(l == 0) dfs2(now + 1, 0, tot, times);
    }
    
    void dfs1(int now, int l, int tot, int times) {//2
    	if(now == 13) {
    		if(l >= 3) {
    			if(times < 4) dfs1(1, 0, tot + 1, times + 1);
    			if(times == 4) dfs2(1, 0, tot + 1, 0);
    		}
    		else if(l == 0) {
    			if(times < 4) dfs1(1, 0, tot, times + 1);
    			if(times == 4) dfs2(1, 0, tot, 0);
    		}
    		return ;
    	}
    	if(card[now] >= 2) {
    		card[now] -= 2;
    		dfs1(now + 1, l + 1, tot, times);
    		card[now] += 2;
    		if(l >= 3) dfs1(now + 1, 0, tot + 1, times);
    	} else {
    		if(l >= 3) dfs1(now + 1, 0, tot + 1, times);
    	}
    	if(l == 0) dfs1(now + 1, 0, tot, times);
    }
    
    void dfs(int now, int l, int tot, int times) {//3
    	if(now == 13) {
    		if(l >= 2) {
    			if(times < 4) dfs(1, 0, tot + 1, times + 1);
    			if(times == 4) dfs1(1, 0, tot + 1, 0);
    		}
    		else if(l == 0) {
    			if(times < 4) dfs(1, 0, tot, times + 1);
    			if(times == 4) dfs1(1, 0, tot, 0);
    		}
    		return ;
    	}
    	if(card[now] >= 3) {
    		card[now] -= 3; 
    		dfs(now + 1, l + 1, tot, times);
    		card[now] += 3;
    		if(l >= 2) dfs(now + 1, 0, tot + 1, times);
    	} else {
    		if(l >= 2) dfs(now + 1, 0, tot + 1, times);
    	}
    	if(l == 0) dfs(now + 1, 0, tot, times);
    }
    
    int main() {
    //	freopen("data.in", "r", stdin);
    	int T; scanf("%d%d", &T, &n);
    	while(T--) {
    		memset(card, 0, sizeof(card));
    		ans = n; flag = false;
    		for(int i = 1, x, y; i <= n; i++) {
    			scanf("%d%d", &x, &y);
    			if(x == 0 && y == 1) card[14]++;
    			else if(x == 0 && y == 2) card[15]++;
    			else card[h[x]]++;
    		}
    		if(card[14] && card[15]) flag = true;
    		dfs(1, 0, 0, 0);
    		printf("%d
    ", ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    出差兰州
    出差乌鲁木齐(3)
    依赖倒置原则
    .NET 打印界面
    出差乌鲁木齐2
    出差乌鲁木齐(2)
    出差乌鲁木齐3
    IStyleGallery.AddItem、UpdateItem、RemoveItem用法
    Shapefile记录检索
    c#利用最小二乘法拟合任意次函数曲线(转)
  • 原文地址:https://www.cnblogs.com/mcggvc/p/14058839.html
Copyright © 2011-2022 走看看