bzoj1007: [HNOI2008]水平可见直线

题目链接

bzoj1007: [HNOI2008]水平可见直线

题解

显然,维护一个下凸壳(是这么叫吧)
按斜率小及大排序
引入直线a
令直线a斜率小与等于直线b时
令a挡住b
那么a与b之前相交的直线c的交点必然在b与c交点的左边
这样a与b的交点才会在直线c的左边
用单调栈维护
斜率与截距都相同时要unique...另外,有些卡精度.....

代码

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
inline int read() {
    int x = 0,f = 1;
    char c = getchar();
    while(c < '0' || c > '9') {if(c == '-' ) f = -1;c = getchar();}
    while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = getchar();
    return x * f;
}
const int maxn = 11; 
int n,m;
int D,val[maxn];
int map[maxn][maxn],fs[6] = {1,0,-1,0,1} ; 
char a[maxn];
int dp[maxn][maxn][1 << maxn];
int ans = 0;
struct Node {
    int x,y,S;
    Node(int x = 0,int y = 0,int S = 0) : x (x),y(y),S(S) {}; 
}loc[maxn * maxn];
//inline int Get_Node(int i ,int j) { return i * (n - 1) + j; }
int Get_Point(int x,int y,int tx,int ty,int S)  {
    for(int i = 0;i < D;++ i) {
        int X = loc[i].x,Y = loc[i].y;
        if(((x < X && tx >= X) || (x >= X && tx < X)) && y > Y) 
            S ^= (1<<i);
    }   
    return S;
} 
void spfa(int I,int J) {
    memset(dp,0x3f,sizeof dp); 
    std::queue<Node>que;que.push(Node(I,J,0)); 
    dp[I][J][0] = 0;
    while(! que.empty()) {
        Node cur = que.front();que.pop();
        for(int j = 0;j < 4;++ j) {
            int tx = cur.x + fs[j],
                ty = cur.y + fs[j + 1];
            if(tx > n || tx < 1 || ty > m || ty < 1 || map[tx][ty] != -1) continue;
            int state = Get_Point(cur.x,cur.y,tx,ty,cur.S);   
            //printf("%d\n",state);
            if(dp[tx][ty][state] > dp[cur.x][cur.y][cur.S] + 1) {
                dp[tx][ty][state] = dp[cur.x][cur.y][cur.S] + 1;
                que.push(Node(tx,ty,state)) ;
            }
        }
    }
    for(int i = 0;i < (1<<D); ++ i) {
        int V = -dp[I][J][i];
        for(int j = 0;j < D;++ j) {
            if((1 << j) & i) V += val[j];
        }
        ans = std::max(ans,V);
    }
}
int main() {
    n = read(),m = read();D = read();
    for(int i = 0;i < D;++ i) val[i] = read(); 
    for(int i = 1;i <= n;++ i) { 
        scanf("%s",a + 1);
        for(int j = 1;j <= m;++ j) {
            if(a[j] >= '0' && a[j] <= '9')  { map[i][j] = a[j] - '0' - 1;loc[map[i][j]] = Node(i,j,0); } 
            else if(a[j] == '#') map[i][j] = 13; 
            else map[i][j] = -1;
        } 
    }   
    for(int i = 1;i <= n;++ i) 
        for(int j = 1;j <= m;++ j) 
            if(map[i][j] == -1) spfa(i,j); 
    printf("%d\n",ans);
    return 0;
}
posted @ 2018-04-28 19:35  zzzzx  阅读(132)  评论(0编辑  收藏  举报