主题思路就是枚举每一个比赛是什么状况
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
int n,tot,s[10],ans,a[10],last[10];
struct aa
{
int u,v;
}c[50];
void dfs(int i)
{
if (i==tot+1)
{
for (int j=1;j<=n;j++) if (a[j]!=s[j]) return ;
ans++;
return ;
}
int u=c[i].u,v=c[i].v,t,p;
if ((last[u]-i+1)*3+a[u]<s[u]) return;//估价函数剪枝,就算后面的所有的比赛都赢的话也不能满足要求就剪掉
if ((last[v]-i+1)*3+a[v]<s[v]) return;
for (int j=0;j<=1;j++)
{
if (j==0) t=u,p=v;else t=v,p=u;
if (i==last[t])
{
if (a[t]+3==s[t]) {a[t]+=3;dfs(i+1);a[t]-=3;}//最难的,当一场比赛是一个人最后一场比赛时,可以直接推出这个比赛应该是什么
else if(a[t]+1==s[t]){a[t]++,a[p]++;if (a[p]<=s[p]) dfs(i+1);a[t]--,a[p]--;}
else if (a[t]==s[t]){a[p]+=3;if (a[p]<=s[p]) dfs(i+1);a[p]-=3;}
return ;
}
}
if (a[u]+3<=s[u]){a[u]+=3;dfs(i+1);a[u]-=3;}//保证不能超过分数,就是一个点当前分数大于总分数时剪掉
if (a[u]+1<=s[u]&&a[v]+1<=s[v]) {a[u]++,a[v]++;dfs(i+1);a[u]--,a[v]--;}
if (a[v]+3<=s[v]){a[v]+=3;dfs(i+1);a[v]-=3;}
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&s[i]);
for (int i=1;i<=n;i++)
{
for (int j=i+1;j<=n;j++) c[++tot].u=i,c[tot].v=j;//搜索顺序剪枝,基本上是一个一个搜,尽量早被剪掉
last[i]=tot;
}
dfs(1);
printf("%d",ans);
return 0;
}
总结
1:现在需要锻炼的是
估价函数剪枝:就算后面都如何,也不能满足条件,这里是就算后面都赢!!!!(最重要)
可行性剪枝
搜索顺序:尽量在刚刚搜索时就剪掉