1. 程式人生 > >【BZOJ1294】[SCOI2009]圍豆豆(動態規劃,狀壓)

【BZOJ1294】[SCOI2009]圍豆豆(動態規劃,狀壓)

bool pre max += 網格 中心 是否 ret algo

【BZOJ1294】[SCOI2009]圍豆豆(動態規劃,狀壓)

題面

BZOJ
洛谷

題解

首先考慮如何判斷一個點是否在一個多邊形內(不一定是凸的),我們從這個點開始,朝著一個方向畫一條射線,看看它和這個多邊形的變相交了幾次,如果是奇數次那麽一定在這個多邊形內,否則不在。
這個可以感性理解一下,如果在內部的話,第一次碰到就是出了這個多邊形,第二次又是進來,第三次又是出去......而最後總會出去,所以是奇數次。如果不在內部的話,顯然就是進去出去是兩兩配對的,也就是偶數次。
那麽我們可以在網格上從每一個豆豆開始向右側畫一條條的射線,那麽和射線交的次數決定了這個豆豆是否在內。同時,放置射線和某條邊界完全重合導致的不好計算,我們可以認為我們圍豆豆的邊在方格中線的偏上位置,而豆豆都恰好在格子的中心,這樣子計算就要求強制跨越中線才算豆豆和這條線有交點,這樣子就不會有問題了。

所以這個時候我們只需要欽定一個起點,設\(f[x][y][S]\)表示當前在點\((x,y)\),並且圍住了\(S\)這些豆豆的最小邊界長度,最後只需要在再回到起點就可以了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
#define ll long long
#define MAX 15
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
char g[MAX][MAX];
int n,m,D,ans=-1e9,v[MAX];
int f[MAX][MAX][1<<9];
int sum[1<<9];
bool vis[MAX][MAX][1<<9];
struct Node{int x,y,S;};
int X[MAX],Y[MAX];
int d[4][2]={1,0,-1,0,0,1,0,-1};
int Get(int fx,int fy,int x,int y,int S)
{
    for(int i=0;i<D;++i)
        if(((fx==X[i]&&x>X[i])||(fx>X[i]&&x<=X[i]))&&y>Y[i])S^=1<<i;
    return S;
}
void SPFA(int x,int y)
{
    queue<Node> Q;memset(f,63,sizeof(f));
    f[x][y][0]=0;Q.push((Node){x,y,0});
    while(!Q.empty())
    {
        int x=Q.front().x,y=Q.front().y,S=Q.front().S;Q.pop();
        for(int i=0;i<4;++i)
        {
            int xx=x+d[i][0],yy=y+d[i][1];
            if(g[xx][yy]!='0')continue;
            int SS=i<2?Get(x,y,xx,yy,S):S;
            if(f[xx][yy][SS]>f[x][y][S]+1)
            {
                f[xx][yy][SS]=f[x][y][S]+1;
                if(!vis[xx][yy][SS])vis[xx][yy][SS]=true,Q.push((Node){xx,yy,SS});
            }
        }
        vis[x][y][S]=false;
    }
    for(int i=0;i<1<<D;++i)
        ans=max(ans,sum[i]-f[x][y][i]);
}
int main()
{
    n=read();m=read();D=read();
    for(int i=0;i<D;++i)v[i]=read();
    memset(g,'#',sizeof(g));
    for(int i=1;i<=n;++i)scanf("%s",g[i]+1),g[i][m+1]='#';
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            if(g[i][j]>='1'&&g[i][j]<='9')
                X[g[i][j]-49]=i,Y[g[i][j]-49]=j;
    for(int i=0;i<1<<D;++i)
        for(int j=0;j<D;++j)
            if(i&(1<<j))sum[i]+=v[j];
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            if(g[i][j]=='0')
                SPFA(i,j);
    printf("%d\n",ans);
    return 0;
}

【BZOJ1294】[SCOI2009]圍豆豆(動態規劃,狀壓)