[SCOI2009]圍豆豆

題目

是否是平時在手機裏玩吃豆豆遊戲玩膩了呢?最近MOKIA手機上推出了一種新的圍豆豆遊戲,你們一塊兒來試一試吧。node

遊戲的規則很是簡單,在一個N×M的矩陣方格內分佈着D顆豆子,每顆豆有不一樣的分值Vi。遊戲者能夠選擇任意一個方格做爲起始格,每次移動能夠隨意的走到相鄰的四個格子,直到最終又回到起始格。最終遊戲者的得分爲全部被路徑圍住的豆豆的分值總和減去遊戲者移動的步數。矩陣中某些格子內設有障礙物,任什麼時候刻遊戲者不能進入包含障礙物或豆子的格子。遊戲者可能的最低得分爲0,即什麼都不作。ios

注意路徑包圍的概念,即某一顆豆在路徑所造成的多邊形(多是含自交的複雜多邊形)的內部。下面有兩個例子:ide

 

第一個例子中,豆在路徑圍成的矩形內部,因此豆被圍住了。第二個例子中,雖然路徑通過了豆的周圍的8個格子,可是路徑造成的多邊形內部並不包含豆,因此沒有圍住豆子。spa

布布最近迷上了這款遊戲,可是怎麼玩都拿不了高分。聰明的你決定寫一個程序來幫助他順利通關。code

Inputxml

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

Output遊戲

僅包含一個整數,爲最高可能得到的分值。get

Sample Inputstring

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。

解說

這道題看着很噁心,作起來更噁心。

首先我試着拿DP的方式來思考:每一個豆子我能夠選能夠不選,圍住一個豆子至少須要8的格的代價,也就是說若是圍了這個豆子的得分比8大的話我就去圍它,而一個點跑到另外一個點的時候就計算下路程,另外一個點帶來的價值比路程大的話就去圍它。對於負數確定是儘可能不圍,可是若是繞過它用的價值比圍它虧損的還大那就圍它……

可是,特殊狀況好多啊。好比幾個豆子連在一塊兒的話圍它們須要的平均價值就不是8了,還有,不能走的格子沒法被歸入這個體系,哦還有究竟什麼算是「繞過負的格子」……這麼複雜的話我還不如研究博弈論呢……

總之,這個思路確定不對。

到最後我真的想不出來了……看看題解吧……

前置知識

如何判斷一個點是否在一個多邊形內部?從這個點向外引一條射線,若與多邊形相交了奇數次,就在它的內部,不然在外部。

正解

d很小,考慮狀壓DP。

預處理出豆子的座標和每一個狀態下全部豆子的得分和sum[S]。

首先枚舉一個起點(x,y)。設f[i][j][S]表示走到了(i,j)這個格子,當前圈住的豆子的狀態爲S的最小邊界長度。顯然這個東西能夠跑一遍最短路獲得,具體實現仍是見代碼。

而後,枚舉狀態S。由於要走一條迴路,因此用sum[S]−f[x][y][S]來更新答案。

最後輸出答案,而後就作完啦。

——引自M_sea's Blog

因此,就這樣,狀壓DP,剛學還不熟練,沒有想到。

代碼

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cstdio>
 5 #include <cmath>
 6 #include <queue>
 7 using namespace std;
 8 
 9 inline int read() {
10     int X=0,w=1; char c=getchar();
11     while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
12     while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
13     return X*w;
14 }
15 
16 const int fx[4][2]={1,0,-1,0,0,1,0,-1};
17 
18 int n,m,d,ans=-2e9;
19 int f[15][15][1<<9]; //f[i][j][S]表示當前在(i,j),圍住的豆豆狀態爲S的最小邊界長度
20 int sum[1<<9]; //sum[S]表示S狀態的總分
21 char g[15][15];
22 int val[15],X[15],Y[15];
23 
24 struct node { int x,y,S; };
25 int dp[15][15][1<<9];
26 
27 
28 int get(int x,int y,int xx,int yy,int S) {
29     for (int i=0;i<d;++i)
30         if (((x==X[i]&&xx>X[i])||(x>X[i]&&xx<=X[i]))&&yy>Y[i]) S^=1<<i;
31     return S;
32 }
33 
34 inline void solve(int x,int y) {
35     queue<node> Q;
36     Q.push((node){x,y,0});
37     memset(f,0x3f,sizeof(f));
38     f[x][y][0]=0,dp[x][y][0]=1;
39     while (!Q.empty()) {
40         node fr=Q.front(); Q.pop();
41         int x=fr.x,y=fr.y,S=fr.S; dp[x][y][S]=0;
42         for (int i=0;i<4;++i) {
43             int X=x+fx[i][0],Y=y+fx[i][1];
44             if (g[X][Y]!='0') continue;
45             int SS=i<2?get(x,y,X,Y,S):S;
46             if (f[x][y][S]+1<f[X][Y][SS]) {
47                 f[X][Y][SS]=f[x][y][S]+1;
48                 if (!dp[X][Y][SS]) {
49                     dp[X][Y][SS]=1;
50                     Q.push((node){X,Y,SS});
51                 }
52             }
53         }
54     }
55     for (int S=0;S<(1<<d);++S)
56         ans=max(ans,sum[S]-f[x][y][S]);
57 }
58 
59 int main() {
60     n=read(),m=read(),d=read();
61     for (int i=0;i<d;++i) val[i]=read();
62     for (int i=1;i<=n;++i) scanf("%s",g[i]+1);
63     for (int i=0;i<=n+1;++i) g[i][0]=g[i][m+1]='#';
64     for (int i=0;i<=m+1;++i) g[0][i]=g[n+1][i]='#';
65     for (int S=0;S<(1<<d);++S)
66         for (int i=0;i<d;++i)
67             if (S&(1<<i)) sum[S]+=val[i];
68     for (int i=1;i<=n;++i)
69         for (int j=1;j<=m;++j)
70             if (g[i][j]>='1'&&g[i][j]<='9')
71                 X[g[i][j]-'1']=i,Y[g[i][j]-'1']=j;
72     for (int i=1;i<=n;++i)
73         for (int j=1;j<=m;++j)
74             if (g[i][j]=='0') solve(i,j);
75     printf("%d\n",ans);
76     return 0;
77 }
View Code

 

幸甚至哉,歌以詠志。

相關文章
相關標籤/搜索