給出一個最大的棋盤,然後棋盤上有黑色或者白色的棋子。每個棋子都有一個權值。現在你要把所有的棋子全部拿走,你有兩種取法:1.任意取走一個棋子,付出這個棋子權值的代價。2.取走一對棋子,付出兩個棋子權值差絕對值的代價,但是必須要滿足的條件是你如果想拿走現在這個棋子,你必須要保證這個棋子作爲右上端點的矩形裏面沒有其它的棋子。求問拿完所有的棋子最小的權值是多少。
首先,單取一個棋子必定劣於取一對棋子,所以只有無法取對的時候才考慮單取。其次,由於數據規模非常小,把取走棋子的狀態壓縮爲一條輪廓線,顯然合法的輪廓線只有條,並且與下方取走哪些棋子一一對應,只需要一個的串表示從起點出發表示向右走,表示向下走。最後,對於當前的這個狀態,在每個的位置上可以選擇取走這個位置上方的一個棋子。
轉移分兩種情況:單取一個合法的/暴力枚舉一對合法的。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define MIN(x,y) (x)<(y)?(x):(y)
const int inf=0x3f3f3f3f;
const int N=(1<<24);
int a[12][12];
char ch[12][12];
int f[N];
inline int get(int S,int bit) { return (S>>bit)&1; }
int main() {
int n;
while(scanf("%d",&n)!=EOF) {
for(int i=0;i<n;i++)
scanf("%s",ch[i]);
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
scanf("%d",&a[i][j]);
}
}
int e=(1<<n)-1,s=e<<n; // right down // down right
fill(f+e,f+s,1e9);
f[s]=0;
for(int S=s;S>e;S--) {
if(__builtin_popcount(S)!=n) continue;
int x=n-1,y=n;
for(int i=0;i+1<2*n;i++) {
if(get(S,i)) x--;
else y--;
if(!get(S,i)&&get(S,i+1)) {
f[S-(1<<i)]=MIN(f[S-(1<<i)],f[S]+(ch[x][y]!='.')*a[x][y]);
int nx=n-1,ny=n;
for(int j=0;j+1<i;j++) {
if(get(S,j)) nx--;
else ny--;
if(!get(S,j)&&get(S,j+1)&&ch[x][y]+ch[nx][ny]=='B'+'W')
f[S-(1<<i)-(1<<j)]=MIN(f[S-(1<<i)-(1<<j)],f[S]+abs(a[x][y]-a[nx][ny]));
}
}
}
}
printf("%d\n",f[e]);
}
return 0;
}