Problem C. Card Game
两次三维DP,没想到还能这样@@
对段【i,j】判断能否被完全消除(j>=i+2),递推公式是
- ( i,m,j) 可以消除,【i+1,m-1】,【m+1,j-1】可以消除(即i,j作为边界两点和中间某个m点一起消除) i<m<j
- 【i,m】可以消除,【m+1,j】可以消除 i+2<=m<j,m+=3
然后对端【i,j】计算最小剩余牌的数目。【i,j】的count初始化为 j-i+1(初始值)
- 0 if 【i,j】能消除
- min{ 【i,m】+【m+1,j】} i<=m<j
#include <iostream>
#include <vector>
using namespace std;
inline bool isValid(int a,int b,int c,int k){
return b-a==k&&c-b==k;
}
//[ x y .....],k
int dp(int a[],int n,int c){
if(n==0) return 0;
vector<vector<bool> > vec(n+1,vector<bool>(n+1,false));
for(int i=1;i<=n;i++) vec[i][i-1]=true;//@important:init edge
for(int i=3;i<=n;i+=3){//@warning:i+=3, a detail
for(int j=1;j+i-1<=n;j++){
int k=j+i-1;
// [j,k]=> j,[j+1,m],m+1,[m+2,k-1],k
for(int m=j;m+2<=k;m+=3){//@error: here m start from j, not j+1
vec[j][k]=(vec[j+1][m]&&vec[m+2][k-1]&&isValid(a[j],a[m+1],a[k],c));
if(vec[j][k]) break;
}
if(!vec[j][k]){
for(int m=j+3;m<k;m+=3){
if(vec[j][m-1]&&vec[m][k]) {
vec[j][k]=true;
break;
}
}
}
}
}
#define maxn 0xfffffff
vector<vector<int> > cnt(n+1,vector<int>(n+1,maxn));
for(int i=1;i<=n;i++){
for(int j=1;j+i-1<=n;j++){
int k=j+i-1;
if(vec[j][k]) {cnt[j][k]=0;continue;}
cnt[j][k]=i;//@important
for(int m=j;m<k;m++)
cnt[j][k]=min(cnt[j][k],cnt[j][m]+cnt[m+1][k]);
}
}
return cnt[1][n];
}
int main(){
int a[10000];
int n;cin>>n;
for(int i=0;i<n;i++){
int m,k;cin>>m>>k;
for(int j=1;j<=m;j++)//@error: a[] start from 1
cin>>a[j];
cout<<"Case #"<<i+1<<": "<<dp(a,m,k)<<endl;
}
return 0;
}
另一种写法:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
const int maxn = 105;
int a[maxn], f[maxn][maxn];
bool d[maxn][maxn];
int diff(int a, int b, int c, int k) {
return c - b == k && b - a == k;
}
int solve() {
int n, K;
cin >> n >> K;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
memset(d, 0, sizeof(d));
for (int i = 1; i <= n; ++i) {
d[i][i - 1] = true;
}
for (int l = 3; l <= n; ++l) {
for (int i = 1; i + l - 1 <= n; ++i) {
int j = i + l - 1;
for (int k = i + 1; k < j; k += 3) {
d[i][j] |= (d[i + 1][k - 1] && d[k + 1][j - 1] && diff(a[i], a[k], a[j], K));
}
for (int k = i + 2; k < j; k += 3) {
d[i][j] |= (d[i][k] && d[k + 1][j]);
}
}
}
for (int i = 1; i <= n; ++i) {
for (int j = i; j <= n; ++j) {
if (d[i][j]) {
f[i][j] = j - i + 1;
} else {
f[i][j] = 0;
}
}
}
for (int l = 3; l <= n; ++l) {
for (int i = 1; i + l - 1 <= n; ++i) {
int j = i + l - 1;
for (int k = i; k < j; ++k) {
f[i][j] = std::max(f[i][j], f[i][k] + f[k + 1][j]);
}
}
}
return n - f[1][n];
}
int main() {
int T;
cin >> T;
for (int t = 1; t <= T; ++t) {
cout << "Case #" << t << ": " << solve() << endl;
}
}