【BZOJ1306】match循环赛

看完题目后看到数据n<=8,
不难想到这题可以写深搜来做

分析

比如说以数据:

3
3 3 3

为例子,
进行了三场比赛:AB AC BC;
我们只要搜索每场比赛,并枚举比赛的三个结果(胜、负、平)并判断能否达到答案的分数即可
如果是三个人:

void dfs(int step) {
    if(step==cs+1){
        int ff=1;
        for(int i=1;i<=n;i++)
            if(a[i]!=s[i]) ff=0;
        if(ff)
            ans++;
        return;
    }
    int x=team3[step][0],y=team3[step][1];//team数组记录了每场比赛的两个参与者
    if(s[x]+3<=a[x]){//结局1 A胜
        s[x]+=3;
        dfs3(step+1);
        s[x]-=3;//回溯
    }
    if(s[y]+3<=a[y]){结局2 B胜
        s[y]+=3;
        dfs3(step+1);
        s[y]-=3;
    }
    if(s[x]+1<=a[x]&&s[y]+1<=a[y]){//结局3 平
        s[x]++;
        s[y]++;
        dfs3(step+1);
        s[y]--;
        s[x]--;
    }
} 

这样搜索的初步就算完成了

然而分析一下时间复杂度

由于我们搜索的是每一局比赛,每个比赛有三种结果,最多可能有(8*7/2==)28场比赛,那么当n==8时,时间复杂度为O(3^28(≈2.2e13)) 若不加剪枝肯定会T;

所以要加上一些剪枝

因为要求方案数,那么肯定最优化剪枝不行
排序?似乎对本题求解没什么帮助
而可行性剪枝在这里可以发挥出作用

如果某个人在这局比赛后每次都赢,但是最终得分仍然低于期望得分,那么这个情况不存在,直接return

还是以三个人为例

上面的代码可以改成这样子:

void dfs(int step) {
    if(step==cs+1){
        int ff=1;
        for(int i=1;i<=n;i++)
            if(a[i]!=s[i]) ff=0;
        if(ff)
            ans++;
        return;
    }

    for(int i=1;i<=n;i++){//剪枝
        if(jz[n][i][step+1]*3+s[i]<a[i])//jz数组记录了总共n个人时第step场比赛后,还有几局比赛的机会(即胜利的可能)
        return;
    }

    int x=team3[step][0],y=team3[step][1];
    if(s[x]+3<=a[x]){
        s[x]+=3;
        dfs3(step+1);
        s[x]-=3;
    }
    if(s[y]+3<=a[y]){
        s[y]+=3;
        dfs3(step+1);
        s[y]-=3;
    }
    if(s[x]+1<=a[x]&&s[y]+1<=a[y]){
        s[x]++;
        s[y]++;
        dfs3(step+1);
        s[y]--;
        s[x]--;
    }

} 

其他的细节比如当n==2||n==1时可以直接输出
还有team数组(可以再写一个test程序直接输出,不用手打):

int team8[50][2]={{1,2},{1,3},{1,4},{1,5},{1,6},{1,7},{1,8},{2,3},{2,4},{2,5},{2,6},{2,7},{2,8},{3,4},{3,5},{3,6},{3,7},{3,8},{4,5},{4,6},{4,7},{4,8},{5,6},{5,7},{5,8},{6,7},{6,8},{7,8}};
int team7[50][2]={{1,2},{1,3},{1,4},{1,5},{1,6},{1,7},{2,3},{2,4},{2,5},{2,6},{2,7},{3,4},{3,5},{3,6},{3,7},{4,5},{4,6},{4,7},{5,6},{5,7},{6,7}};
int team6[50][2]={{1,2},{1,3},{1,4},{1,5},{1,6},{2,3},{2,4},{2,5},{2,6},{3,4},{3,5},{3,6},{4,5},{4,6},{5,6}};
int team5[50][2]={{1,2},{1,3},{1,4},{1,5},{2,3},{2,4},{2,5},{3,4},{3,5},{4,5}};
int team4[50][2]={{1,2},{1,3},{1,4},{2,3},{2,4},{3,4}};
int team3[50][2]={{1,2},{1,3},{2,3}};

这样大概…就可以AC了吧

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值