1. 程式人生 > >[BZOJ1294][SCOI2009]圍豆豆Bean 射線法+狀壓dp+spfa

[BZOJ1294][SCOI2009]圍豆豆Bean 射線法+狀壓dp+spfa

online rip 矩陣 lap else ios closed 說明 geo

1294: [SCOI2009]圍豆豆Bean

Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 458 Solved: 305
[Submit][Status][Discuss]

Description

技術分享

Input

第一行兩個整數N和M,為矩陣的邊長。 第二行一個整數D,為豆子的總個數。 第三行包含D個整數V1到VD,分別為每顆豆子的分值。 接著N行有一個N×M的字符矩陣來描述遊戲矩陣狀態,0表示空格,#表示障礙物。而數字1到9分別表示對應編號的豆子。

Output

僅包含一個整數,為最高可能獲得的分值。

Sample Input

3 8
3
30 -100 30
00000000
010203#0
00000000

Sample Output

38

HINT

50%的數據滿足1≤D≤3。
100%的數據滿足1≤D≤9,1≤N, M≤10,-10000≤Vi≤10000。

從每個豆豆射出一條射線,若經過路線奇數次則說明路線將其包圍,若經過偶數次則不包圍。

設狀態f[i][j][k]表示到達(i,j)圍豆豆狀態為k的最大價值。

每次枚舉起點,用spfa轉移即可。

技術分享
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cstdlib>
 5 #include<cmath>
 6
#include<algorithm> 7 #define maxn 15 8 using namespace std; 9 int tx[5]={1,-1,0,0}; 10 int ty[5]={0,0,1,-1}; 11 char a[maxn]; 12 int num[maxn][maxn]; 13 int val[maxn]; 14 int n,m,d; 15 int x[maxn],y[maxn]; 16 int f[maxn][maxn][600]; 17 int inq[maxn][maxn][600]; 18 int ans=0; 19 struct data { 20 int
x,y,z; 21 }q[10000]; 22 void work(int i,int j) { 23 memset(f,-97,sizeof(f)); 24 int head=0,tail=1; 25 q[0]=(data){i,j,0}; 26 f[i][j][0]=0; 27 while(head!=tail) { 28 data now=q[head++];if(head==9000) head=0; 29 if(now.x==i&&now.y==j) ans=max(ans,f[now.x][now.y][now.z]); 30 for(int k=0;k<4;k++) { 31 int tox=now.x+tx[k],toy=now.y+ty[k],toz=now.z; 32 int add=0; 33 if(tox<1||toy<1||tox>n||toy>m||num[tox][toy]!=0) continue; 34 if(now.x!=tox) { 35 data temp; 36 if(tox>now.x) temp=(data){now.x,now.y,now.z};else temp=(data){tox,toy,now.z}; 37 for(int l=1;l<=d;l++) { 38 if(temp.y>y[l]&&temp.x==x[l]) { 39 temp.z^=(1<<(l-1)); 40 if(temp.z&(1<<(l-1))) add+=val[l]; 41 else add-=val[l]; 42 } 43 } 44 toz=temp.z; 45 } 46 if(f[tox][toy][toz]<f[now.x][now.y][now.z]+add-1){ 47 f[tox][toy][toz]=f[now.x][now.y][now.z]+add-1; 48 if(!inq[tox][toy][toz]) { 49 q[tail++]=(data){tox,toy,toz};if(tail==9000) tail=0; 50 inq[tox][toy][toz]=1; 51 } 52 } 53 inq[now.x][now.y][now.z]=0; 54 } 55 } 56 } 57 int main() { 58 scanf("%d%d%d",&n,&m,&d); 59 for(int i=1;i<=d;i++) scanf("%d",&val[i]); 60 for(int i=1;i<=n;i++) { 61 scanf("%s",a+1); 62 for(int j=1;j<=m;j++) { 63 if(a[j]==0) num[i][j]=0; 64 else if(a[j]!=#) x[a[j]-0]=i,y[a[j]-0]=j,num[i][j]=-1; 65 else num[i][j]=1; 66 } 67 } 68 for(int i=1;i<=n;i++) 69 for(int j=1;j<=m;j++) 70 if(num[i][j]==0) work(i,j); 71 printf("%d",ans); 72 return 0; 73 }
View Code

[BZOJ1294][SCOI2009]圍豆豆Bean 射線法+狀壓dp+spfa