题解 [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;
}

posted @ 2019-01-22 14:01  ZenyZ  阅读(202)  评论(1编辑  收藏  举报