BZOJ1294: [SCOI2009]围豆豆Bean
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1294
状压dp,dis[s][i][j]表示从(i,j)出发围的状态是s的最短路。
然后判断一个点是否在区间内用射线法(向右射出一条射线,如果穿过的边界是奇数就算,偶数则不算。
然后枚举起点跑最短路就可以了。
(傻叉错误调半天TAT
#include<cstring> #include<cstdio> #include<iostream> #include<algorithm> #include<bitset> #include<queue> #define rep(i,l,r) for (int i=l;i<=r;i++) #define down(i,l,r) for (int i=l;i>=r;i--) #define clr(x,y) memset(x,y,sizeof(x)) using namespace std; struct data{int x,y,z; }; int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0}; int mp[15][15],dis[1101][15][15],d[1101][15][15],vis[1101][15][15],v[15],p[15][2],bin[15]; int n,m,D,tot,ans; int read(){ int x=0,f=1; char ch=getchar(); while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();} while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} return x*f; } int get(int s,int x,int y,int xx,int yy){ int ans=s; rep(i,1,D) { int nowx=p[i][0],nowy=p[i][1]; if (yy>nowy&&((x<=nowx&&xx>nowx)||(x>nowx&&xx<=nowx))) ans=ans^bin[i-1]; } return ans; } void spfa(int x,int y){ queue<data> q; clr(dis,127); clr(vis,0); dis[0][x][y]=0; q.push((data){x,y,0}); while (!q.empty()){ data u=q.front(); q.pop(); vis[u.z][u.x][u.y]=1; rep(i,0,3){ int vx=u.x+dx[i],vy=u.y+dy[i]; if (mp[vx][vy]!=0) continue; int tmp=get(u.z,u.x,u.y,vx,vy); if (dis[tmp][vx][vy]>dis[u.z][u.x][u.y]+1) { dis[tmp][vx][vy]=dis[u.z][u.x][u.y]+1; if (!vis[tmp][vx][vy]){ vis[tmp][vx][vy]=1; q.push((data){vx,vy,tmp}); } } } vis[u.z][u.x][u.y]=0; } rep(i,0,(1<<D)-1) { int tmp=-dis[i][x][y]; rep(j,1,D) if (i&bin[j-1]) tmp+=v[j]; ans=max(ans,tmp); } } int main(){ bin[0]=1; rep(i,1,10) bin[i]=bin[i-1]*2; n=read(); m=read(); D=read(); rep(i,1,D) v[i]=read(); clr(mp,-1); rep(i,1,n) rep(j,1,m){ char ch=getchar(); while (!isdigit(ch)&&ch!='#') ch=getchar(); if (ch=='#') continue; else mp[i][j]=ch-'0'; if (ch!='0') p[ch-'0'][0]=i,p[ch-'0'][1]=j; } ans=0; rep(i,1,n) rep(j,1,m) if (mp[i][j]==0)spfa(i,j); printf("%d\n",ans); return 0; }