• 题解 [HNOI2013]比赛


    一道不错的搜索题

    题目

    题面很简单,n支队伍循环赛,只知道最后各个队的得分,求可能的比赛情况数量

    看数据范围只有10,上搜索

    1.裸暴力

    应该很好打,直接枚举每一场比赛的得分情况,然后check

    复杂度(O(3^{n*(n-1)/2})),可以过40pts

    dfs中的x,y表示谁和谁比赛

    score是枚举比赛情况所推出的分数

    void dfs(int x,int y)
    {
        if(x==n-1&&y==n+1)
        {
            if(check())ans++;
            return;
        }
        
        if(y>n){dfs(x+1,x+2);return;}
        
        ++score[x],++score[y];
        if(score[x]<=a[x]&&score[y]<=a[y])
        {++nowt,dfs(x,y+1),--nowt;}
        --score[x],--score[y];
    
        score[x]+=3;if(score[x]<=a[x]){++noww,dfs(x,y+1),--noww;}score[x]-=3;
    
        score[y]+=3;if(score[y]<=a[y]){++noww,dfs(x,y+1),--noww;}score[y]-=3;
    }
    

    2.剪枝

    (1)如果当前的分数(score)已经超过了结果分数(a),因为不可能扣分,所以肯定不能满足条件(在以上代码有体现)

    (2)如果某一队在剩下的所有场次中获胜都不能达到结果分数,那么也不能满足条件

        if(score[x]+3*(n-y+1)<a[x])return ;
    

    (3)限制获胜和平局的场数.这个可以通过所有队伍的分数总和以及队伍数求出

        win=sum-n*(n-1),tie=n*(n-1)/2-win;
    

    这样可以得60pts

    3.记忆化

    这个题目最关键的步骤

    其实最后的结果数只和每个队伍的分数以及队伍数有关

    在搜索一个队伍的状态下,到下一层时,可以

    那么可以用记忆化,

    通过hash存储对应情况下的得分情况

    记得排序以排除冗余状态

    AC代码:

    #include<bits/stdc++.h>
    #define il inline 
    #define R register int
    #define ll long long
    #define gc getchar
    #define mod 1000000007
    using namespace std;
    il int rd()
    {
        R x=0,flag=1;
        char ch=0;
        while((ch>'9'||ch<'0')&&ch!='-')ch=gc();
        if(ch=='-')flag=-1,ch=gc();
        while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=gc();
        return x*flag;
    }
    map<ll,ll> mp;
    const int P=28;
    int a[20],score[20],res[20],n,ans,sum;
    int tie,win,nowt,noww;
    inline bool check()
    {
        int i=1;
        while(score[i]==a[i]&&i<=n)i++;
        if(i==n+1)return true;
        else return false;
    }
    ll dfs(int x,int y)
    {
        if(x==n)
        	return 1;
        	
        if(score[x]+3*(n-y+1)<a[x])return 0;//不加的话会错
    
        if(y>n)
        {
            ll state=0;
            for(R i=x+1;i<=n;i++)
                res[i]=a[i]-score[i];
            sort(res+x+1,res+n+1);
            for(R i=x+1;i<=n;i++)
                state=state*P+res[i];//因为要排序,所以分开写
            if(mp.find(state)!=mp.end())return mp[state];
            mp[state]=dfs(x+1,x+2);
            return mp[state];
        }
        
        ll cnt=0;
        ++score[x],++score[y];
        if(score[x]<=a[x]&&score[y]<=a[y]&&nowt<tie)
        {++nowt,cnt+=dfs(x,y+1),--nowt;}
        --score[x],--score[y];
    
        score[x]+=3;
        if(score[x]<=a[x]&&noww<win){++noww,cnt+=dfs(x,y+1),--noww;}
        score[x]-=3;
    
        score[y]+=3;
        if(score[y]<=a[y]&&noww<win){++noww,cnt+=dfs(x,y+1),--noww;}
        score[y]-=3;
        
        return cnt;
    }
    int main ()
    {
    //	freopen("match.in","r",stdin);
    //	freopen("match.out","w",stdout);
        n=rd();
        for(R i=1;i<=n;i++)a[i]=rd(),sum+=a[i];
        win=sum-n*(n-1),tie=n*(n-1)/2-win;
        sort(a+1,a+n+1);
        cout<<dfs(1,2)%mod<<endl;
        return 0;
    }
    
    
  • 相关阅读:
    pandas DataFrame(5)-合并DataFrame与Series
    pandas Series的sort_values()方法
    np.corrcoef()方法计算数据皮尔逊积矩相关系数(Pearson's r)
    switch case 多个处理方式涉及到销售优惠折扣方案处理
    标量函数取规则名称
    调用企业微信接口发送消息
    C#中NameValueCollection类用法 读取配置信息
    .NET Datable分解数据表
    触发器批量业务操作实现方式 update触发器用游标处理
    Lamda OrderBy 排序问题
  • 原文地址:https://www.cnblogs.com/Zenyz/p/10303471.html
Copyright © 2020-2023  润新知