zoukankan      html  css  js  c++  java
  • 【BZOJ1294】[SCOI2009]围豆豆Bean 射线法+状压DP+SPFA

    【BZOJ1294】[SCOI2009]围豆豆Bean

    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[a][b][S]表示当前走到(a,b),已经围住的豆豆状态为S的最短路。转移因为存在环,所以要用SPFA。但是问题在于,如何判断一个豆豆是否被我们围住了呢?

    这里采用射线法:我们从每个豆豆向右引一条射线,如果这条射线与路径有奇数个交点则被围住,否则不被围住。但是可能存在我们顺着射线走的情况。于是将射线向下移动半格即可。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    using namespace std;
    const int maxn=(1<<9)+3;
    int f[10][10][maxn],val[maxn];
    int inq[10][10][maxn],v[10],tr[10][10],dx[]={1,0,-1,0},dy[]={0,1,0,-1};
    char s[10][10];
    queue<int> q1,q2,q3;
    int n,m,K,ans;
    int main()
    {
    	scanf("%d%d%d",&n,&m,&K);
    	int i,j,k,S,T,a,b,c,d;
    	for(i=0;i<K;i++)	scanf("%d",&v[i]);
    	for(i=1;i<(1<<K);i++)
    	{
    		for(j=0;j<K;j++)	if((i>>j)&1)
    		{
    			val[i]=val[i^(1<<j)]+v[j];
    			break;
    		}
    	}
    	for(i=0;i<n;i++)
    	{
    		scanf("%s",s[i]);
    		S=0;
    		for(j=0;j<m;j++)
    		{
    			if(s[i][j]>='1'&&s[i][j]<='9')	S|=1<<(s[i][j]-'1');
    			tr[i][j]=S;
    		}
    	}
    	for(i=0;i<n;i++)	for(j=0;j<m;j++)	if(s[i][j]=='0')
    	{
    		memset(f,0x3f,sizeof(f));
    		f[i][j][0]=0;
    		q1.push(i),q2.push(j),q3.push(0);
    		while(!q1.empty())
    		{
    			a=q1.front(),b=q2.front(),S=q3.front(),inq[a][b][S]=0,q1.pop(),q2.pop(),q3.pop();
    			if(a==i&&b==j)
    			{
    				ans=max(ans,val[S]-f[a][b][S]);
    			}
    			for(k=0;k<4;k++)
    			{
    				c=a+dx[k],d=b+dy[k];
    				if(c<0||c==n||d<0||d==m||s[c][d]!='0')	continue;
    				T=S;
    				if(k==0)	T^=tr[a][b];
    				if(k==2)	T^=tr[c][d];
    				if(f[c][d][T]>f[a][b][S]+1)
    				{
    					f[c][d][T]=f[a][b][S]+1;
    					if(!inq[c][d][T])	inq[c][d][T]=1,q1.push(c),q2.push(d),q3.push(T);
    				}
    			}
    		}
    	}
    	printf("%d",ans);
    	return 0;
    }
  • 相关阅读:
    [CF1398A-E] Codeforces Round 93
    bzoj3758 数数和bzoj3798 特殊的质数
    P4234 最小差值生成树
    [UOJ274] P6664 温暖会指引我们前行
    P4172 [WC2006]水管局长
    bzoj2959 长跑
    bzoj4998 星球联盟(lct+并查集维护动态双连通性)
    P1501 [国家集训队]Tree II
    link-cut-tree
    fhq-treap,splay 模板
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8595556.html
Copyright © 2011-2022 走看看