BZOJ 1306: [CQOI2009]match循环赛

搜索剪枝
不难的一道题。。然而是省选题。。
枚举每场比赛,枚举编号较小的一队的结果,相应的较大的也可以推出结果
当有某一队剩下比赛全赢也比给定分数低就剪枝
当有某一队当前比分超过给定分数也剪枝
只要你把这俩个剪枝加上,然后提交,你就会神奇的发现


为什么还是狂 T???


我还是 too naive ,还是被极限数据卡了。。
所以要在加一个,当这个队伍是和最后一支队伍比赛的时候,只要一种答案,如果和分数相差 0,3,1 时就搜剩下的一个相应的状态,相差 2 就剪枝
。。。我以为这个优化毫无卵用,然而TM居然是有用的。。


代码:

#include
#include
#include
#include
#define g getchar()
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
inline ll read(){
    ll x=0,f=1;char ch=g;
    for(;ch<'0'||ch>'9';ch=g)if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=g)x=x*10+ch-'0';
    return x*f;
}
inline void out(ll x){
    int a[25],t=0;
    if(x<0)putchar('-'),x=-x;
    for(;x;x/=10)a[++t]=x%10;
    for(int i=t;i;--i)putchar('0'+a[i]);
    if(t==0)putchar('0');
    putchar('\n');
}
int n,a[10],f[10],ans;
int opt1[4]={0,3,1,0},opt2[4]={0,0,1,3};
bool pd(){
    for(int i=1;i<=n;++i)if(a[i]!=f[i])return 0;
    return 1;
}
void dfs(int x,int y){
    if(x==n){if(pd())++ans;return;}bool fl=0;
    if(y==n){
        int t1=f[x],t2=f[y];
        if(a[x]-f[x]==2||a[x]-f[x]>3)return;
        int opt=a[x]-f[x];
        if(opt==1)f[x]=a[x],f[y]++;
        else f[x]=a[x],f[y]+=3-opt;
        dfs(x+1,x+2);
        f[x]=t1,f[y]=t2;
    }
    else
    for(int j=1;j<=3;++j){
        f[x]+=opt1[j],f[y]+=opt2[j];
        if(f[x]+(n-y)*3continue;}
        if(f[x]>a[x]){f[x]-=opt1[j],f[y]-=opt2[j];continue;}
        if(f[y]>a[y]){f[x]-=opt1[j],f[y]-=opt2[j];continue;}
        if(f[y]+(n-x-1)*3continue;}
        dfs(x,y+1);
        f[x]-=opt1[j],f[y]-=opt2[j];
    }
}
int main(){
    n=read();
    for(int i=1;i<=n;++i)a[i]=read();
    dfs(1,2);
    out(ans);
    return 0;
}

跑了 8000+ms 9000??? )我真是菜的可以。。

你可能感兴趣的:(搜索,bzoj)