理工 校赛 题

lzp穿鞋带的理论方法

发布时间: 2017年12月11日 14:01   最后更新: 2017年12月11日 14:46   时间限制: 1000ms   内存限制: 128M

对于鞋,lzp有一套奇怪的穿鞋带理论:

0.鞋带孔之间的鞋带不能是弯的,即鞋带穿过两鞋带孔时必须绷直。

1.鞋带必须从最前面的一头左端穿入,并从最前面右端穿出,如图所示为一些普qi通pa的穿鞋带方法,○表示鞋带孔,直线表示鞋带。

c7d12bb4edd31959a7136abbddc237e5.png14ac3b41ef97c2b7419b4626b5ea2d9b.png

shoe5.png

2.穿鞋带时,必须左右交替,如上图所示

3.穿完的鞋带必须存在m个以上的交点,上图左边的共有四个交点,右边的有九个交点。lzp的鞋保证所有交点都只被鞋带经过两次。

现在,lzp想知道,对于每只纵向排列着n对鞋带孔的鞋,有几种穿鞋带方案符合他的理论(上图中n=5)

第一行输入组数T(T<=10)
每组数据输入两个数n(1<=n<=7),m(0<=m<=1000)

对于每组数据输出一行,符合lzp的理论的穿鞋带方案数

7
5 4
5 9
3 2
1 0
3 6
7 10
6 20
576
540
4
1
1
518269
10221

题目分析 : 每次只能重一个点穿过,并且左右交替,点数不多 最多只有7个,那不就是暴力吗,想想要怎么暴力,每次可以交替枚举出所有可能的边,枚举出所有可能的边以后,
在判断当前的这些边总共有多少个交点,怎么判断两个点是不是相交呢,如果给两列点瞬时标上号,那么(a[1]-a[2])*(b[1]-b[2]) < 0,则说明两条线是相交的,自己可以举几个例子验证一下。

代码示例 :
const int eps = 1e6+5;
const double pi = acos(-1.0);
const int inf = 1<<29;
#define Max(a,b) a>b?a:b
#define Min(a,b) a>b?b:a
#define ll long long

int p2[20];
int p1[20];

struct node
{
    int a, b;
}pre[eps];

int sign = 1;
int p;
ll ans = 0;
int n, m;


bool check(){
    int k = 1;
    for(int i = 2; i <= n; i++){
        pre[k].a = i;
        pre[k++].b = p1[i];
    }    
    for(int i = 1; i <= n; i++){
        pre[k].a = p2[i];
        pre[k++].b = i;
    }
    //printf("k = %d
", k);
    int cnt = 0;
    for(int i = 1; i < k; i++){
        for(int j = i+1; j < k; j++){
            if ((pre[i].a - pre[j].a)*(pre[i].b - pre[j].b) < 0){
                cnt++;
            }
        }
    }
    if (cnt >= m) return true;
    else return false;
}

void find(int x){
    for(int i = 2; i <= n; i++){
        //if (x == 1) printf("** %d 
", sign);
        if (sign && !p2[i]) {
            p2[i] = x;
            sign = 0;
            find(i);
            p2[i] = 0;
            sign = 1;
            
        }
        else if (!sign && !p1[i]){
            p1[i] = x;
            sign = 1;
            p = i;
            find(i);
            p1[i] = 0;
            sign = 0;
        }   
    }
    int t = 0;
    for(int i = 2; i <= n; i++){
        if (p2[i]) t++;
    }
    if (sign && t == n-1) {
        sign = 0;
        p2[1] = p;
        
        if (check()) ans++;
        p2[1] = 0; 
    }
}

int main() {
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    int t;
    
    
    cin >> t;
    while(t--){
        scanf("%d%d", &n, &m); 
        
        memset(p2, 0, sizeof(p2));
        memset(p1, 0, sizeof(p1));
        ans = 0, sign = 1;
        find(1); 
        printf("%lld
", ans);
        
    }

    return 0;
}
东北日出西边雨 道是无情却有情
原文地址:https://www.cnblogs.com/ccut-ry/p/8029118.html