传送门
拿到这道题我开始想了想有没有什么递推关系?然后想了想状压DP?
均无果……
开始写搜索,练习赛是只拿到了70分(暴力+剪枝),对每一场比赛搜索……
看题解才发现是记忆化搜索。在搜索的时候可以将当前状态Hash下来。应为每个队最多只打9场比赛,所以最大得分27分,只有10个队伍,用28进制int64能装下。
而且不应该一场比赛一场比赛的搜,这样就不好利用之前的状态(因为这道题里每个人是等价的,所以K个人的方案数可以由对应的K-1个人的方案数和这个人的胜负情况求得)
下面给出上述的两个代码
70分
#include<cstdio>
#include<algorithm>
using namespace std;
char n, w[15], a[105], b[105], cnt, sum, q[105], c[105];
int ans;
inline bool cmp(char x, char y) {
return w[a[x]] + w[b[x]] < w[a[y]] + w[b[y]];
}
void dfs(char u, char tot) {
if(tot + (cnt - u + 1)*2 > sum || tot + (cnt - u + 1)*3 < sum) return;
if(u == cnt+1) { ++ ans; return; }
char p = q[u]; -- c[a[p]]; -- c[b[p]];
if(w[a[p]] >= 3 && c[b[p]]*3 >= w[b[p]]) {
w[a[p]] -= 3;
dfs(u+1, tot + 3);
w[a[p]] += 3;
}
if(w[b[p]] >= 3 && c[a[p]]*3 >= w[a[p]]) {
w[b[p]] -= 3;
dfs(u+1, tot + 3);
w[b[p]] += 3;
}
if(w[a[p]] && w[b[p]] && c[b[p]]*3+1 >= w[b[p]] && c[a[p]]*3+1 >= w[a[p]]) {
w[a[p]] --; w[b[p]] --;
dfs(u+1, tot + 2);
w[a[p]] ++; w[b[p]] ++;
}++ c[a[p]]; ++ c[b[p]];
}
int main() {
scanf("%d", &n);
for(char i = 0; i < n; ++ i) {
scanf("%d", w + i);
sum += w[i];
}
for(char i = 0; i < n; ++ i)
for(char j = i+1; j < n; ++ j) {
++ cnt; a[cnt] = i; b[cnt] = j;
q[cnt] = cnt; ++ c[i]; ++ c[j];
if(a[cnt] < b[cnt]) swap(a[cnt], b[cnt]);
}
sort(q + 1, q + 1 + cnt, cmp);
dfs(1, 0);
printf("%d\n", ans);
return 0;
}
AC代码:
/**************************************************************
Problem: 3139
User: geng4512
Language: C++
Result: Accepted
Time:592 ms
Memory:1736 kb
****************************************************************/
#include<cstdio>
#include<map>
#include<algorithm>
using namespace std;
typedef unsigned long long LL;
int n;
map<LL, int> mp;
inline bool cmp(int a, int b) {
return a > b;
}
struct Sta {
int a[12];
inline LL Hash() {
LL tmp = 0;
for(int i = 0; i <= a[0]; ++ i)
tmp = tmp * 28 + a[i];
return tmp;
}
}a;
int dfs(int st, Sta s) {
int t = s.a[0];
if(t == 1) return 0;
if(s.a[t] > st*3) return 0;
if(st < 1) {
sort(s.a+1, s.a+t+1, cmp);
-- s.a[0]; LL p = s.Hash();
if(mp.count(p)) return mp[p];
return mp[p] = dfs(s.a[0]-1, s);
}
int res = 0;
if(s.a[t] >= 3) {
s.a[t] -= 3;
res += dfs(st-1, s);
s.a[t] += 3;
}
if(s.a[t] >= 1 && s.a[st] >= 1) {
-- s.a[t]; -- s.a[st];
res += dfs(st-1, s);
++ s.a[t]; ++ s.a[st];
}
if(s.a[st] >= 3) {
s.a[st] -= 3;
res += dfs(st-1, s);
s.a[st] += 3;
}
if(st == t-1) return mp[s.Hash()] = res;
return res;
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; ++ i)
scanf("%d", a.a+i);
sort(a.a+1, a.a+n+1, cmp);
a.a[0] = n;
mp[28] = 1;
int ans = dfs(n-1, a);
printf("%d\n", ans);
return 0;
}