zoukankan      html  css  js  c++  java
  • 【BZOJ1294】[SCOI2009]围豆豆(动态规划,状压)

    【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
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Python数据分析与机器学习-Matplot_2
    Python数据分析与机器学习-Matplot_1
    1008. 数组元素循环右移问题 (20)
    Latex小技巧
    执行PowerShell脚本的时候出现"在此系 统上禁止运行脚本"错误
    Linux使用MentoHust联网线上校园网, 回到普通有线网络却连不上?
    Re:uxul
    Linux下nautilus的右键快捷菜单项设置
    从入门到入狱——搭讪技巧
    Latex命令
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9747731.html
Copyright © 2011-2022 走看看