HZOJ 光
一道大模拟,打的我要吐了。
先说一下60%暴力吧,其实模拟光的路线即可,最好还是把边界设为障碍,这样就不用判边界了。最后输出n*m可以骗到10分。
注意不要把n和m弄混(愁死我了)。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<vector> 5 #define LL long long 6 #define int LL 7 using namespace std; 8 int n,m,k,xs,ys,f; 9 char te[10]; 10 bool map[2010][2010]; 11 vector<short> v[1010][1010]; 12 void dfs(int x,int y,int num,int fx) 13 { 14 // cout<<x<<" "<<y<<" "<<fx<<endl; 15 if(v[x][y].size()==0)num++; 16 for(int i=0;i<v[x][y].size();i++)if(v[x][y][i]==fx){cout<<num<<endl;exit(0);} 17 v[x][y].push_back(fx); 18 if(fx==1) 19 { 20 if(x==1&&y==m)dfs(x,y,num,3); 21 else if(map[x-1][y]&&map[x-1][y+1]&&map[x][y+1])dfs(x,y,num,3); 22 else if(x==1||(y<m&&map[x-1][y]&&map[x-1][y+1]))dfs(x,y+1,num,2); 23 else if(y==m||(x>1&&map[x][y+1]&&map[x-1][y+1]))dfs(x-1,y,num,4); 24 else if(map[x-1][y+1])dfs(x,y,num,3); 25 else dfs(x-1,y+1,num,fx); 26 } 27 else if(fx==2) 28 { 29 if(x==n&&y==m)dfs(x,y,num,4); 30 else if(map[x+1][y]&&map[x+1][y+1]&&map[x][y+1])dfs(x,y,num,4); 31 else if(x==n||(y<m&&map[x+1][y]&&map[x+1][y+1]))dfs(x,y+1,num,1); 32 else if(y==m||(x<n&&map[x][y+1]&&map[x+1][y+1]))dfs(x+1,y,num,3); 33 else if(map[x+1][y+1])dfs(x,y,num,4); 34 else dfs(x+1,y+1,num,fx); 35 }//A 36 else if(fx==3) 37 { 38 if(x==n&&y==1)dfs(x,y,num,1); 39 else if(map[x+1][y]&&map[x+1][y-1]&&map[x][y-1])dfs(x,y,num,1); 40 else if(x==n||(y>1&&map[x+1][y]&&map[x+1][y-1]))dfs(x,y-1,num,4); 41 else if(y==1||(x<n&&map[x][y-1]&&map[x+1][y-1]))dfs(x+1,y,num,2); 42 else if(map[x+1][y-1])dfs(x,y,num,1); 43 else dfs(x+1,y-1,num,fx); 44 } 45 else if(fx==4) 46 { 47 if(x==1&&y==1)dfs(x,y,num,2); 48 else if(map[x-1][y]&&map[x-1][y-1]&&map[x][y-1])dfs(x,y,num,2); 49 else if(x==1||(y>1&&map[x-1][y]&&map[x-1][y-1]))dfs(x,y-1,num,3); 50 else if(y==1||(x>1&&map[x][y-1]&&map[x-1][y-1]))dfs(x-1,y,num,1); 51 else if(map[x-1][y-1])dfs(x,y,num,2); 52 else dfs(x-1,y-1,num,fx); 53 } 54 } 55 signed main() 56 { 57 // freopen("ray0.in","r",stdin); 58 59 cin>>n>>m>>k; 60 if(n>1000||m>1000) {cout<<n*m<<endl;exit(0);} 61 int a,b; 62 for(int i=1;i<=k;i++) 63 { 64 cin>>a>>b; 65 if(n<=1000&&m<=1000)map[a][b]=1; 66 } 67 cin>>xs>>ys>>te; 68 for(int i=0;i<=m+1;i++)map[0][i]=map[n+1][i]=1; 69 for(int i=0;i<=n+1;i++)map[i][0]=map[i][m+1]=1; 70 if(te[0]=='N') 71 { 72 if(te[1]=='E')f=1; 73 else f=4;//W 74 } 75 else//S 76 { 77 if(te[1]=='E')f=2; 78 else f=3;//W 79 } 80 if(n<=1000&&m<=1000) 81 dfs(xs,ys,0,f); 82 }
然后说正解(其实就是优化了暴力):
确实有点难以理解,对于光的路线,可以发现其实暴力中间枚举了很多无用的状态,怎么解决呢?
有一个比较简单但是不好想的规律,对于斜线,x+y或x-y不变,那么我们就可以用这个数字代表一条斜线,对于每一条斜线开一个set,将这条斜线上的障碍的x插入,那么二分查找就可以实现快速地转移了。
然而这样递归下去还是比较麻烦的,可以用循环。
再说两个规律:光线经过的路径只可能是环而不是环+链(显然),一条路径中至多出现两次原路返回的情况(这个自己想想也不难,其实是我不会证)。
所以循环处理即可,具体见代码。
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<set> 7 #include<map> 8 #define LL long long 9 #define MAXN 200010 10 #define MP(a,b) make_pair(a,b) 11 #define ma(x) memset(x,0,sizeof(x)) 12 using namespace std; 13 int n,m,k; 14 int xs,ys;char te[10]; 15 LL ans=0; 16 struct rec{int x,y,d;}; 17 set<int> s1[MAXN],s2[MAXN]; 18 map<pair<int,int>,bool>mp; 19 int getid(int x,int y,int d){return d==1?x-y+m+1:x+y;} 20 bool same(rec a,rec b){if(a.x==b.x&&a.y==b.y&&a.d==b.d)return 1;return 0;} 21 bool check(int x,int y){return mp[MP(x,y)];} 22 void add(int x,int y) 23 { 24 s1[getid(x,y,1)].insert(x); 25 s2[getid(x,y,2)].insert(x); 26 mp[MP(x,y)]=1; 27 } 28 pair<rec,int> dfs(rec u) 29 { 30 rec re; 31 set<int>::iterator it; 32 if(u.d==1) 33 { 34 it=s1[getid(u.x,u.y,1)].lower_bound(u.x);it--; 35 re.x=u.x-(abs(*it-u.x)-1); 36 re.y=u.y-(abs(*it-u.x)-1); 37 if(check(re.x-1,re.y)&&check(re.x,re.y-1))re.d=3; 38 else if(check(re.x-1,re.y))re.d=4,re.y--; 39 else if(check(re.x,re.y-1))re.d=2,re.x--; 40 else re.d=3; 41 } 42 if(u.d==2) 43 { 44 it=s2[getid(u.x,u.y,2)].lower_bound(u.x);it--; 45 re.x=u.x-(abs(*it-u.x)-1); 46 re.y=u.y+(abs(*it-u.x)-1); 47 48 if(check(re.x-1,re.y)&&check(re.x,re.y+1))re.d=4; 49 else if(check(re.x-1,re.y))re.d=3,re.y++; 50 else if(check(re.x,re.y+1))re.d=1,re.x--; 51 else re.d=4; 52 } 53 if(u.d==3) 54 { 55 it=s1[getid(u.x,u.y,1)].lower_bound(u.x); 56 re.x=u.x+(abs(*it-u.x)-1); 57 re.y=u.y+(abs(*it-u.x)-1); 58 59 if(check(re.x+1,re.y)&&check(re.x,re.y+1))re.d=1; 60 else if(check(re.x+1,re.y))re.d=2,re.y++; 61 else if(check(re.x,re.y+1))re.d=4,re.x++; 62 else re.d=1; 63 } 64 if(u.d==4) 65 { 66 it=s2[getid(u.x,u.y,2)].lower_bound(u.x); 67 re.x=u.x+(abs(*it-u.x)-1); 68 re.y=u.y-(abs(*it-u.x)-1); 69 70 if(check(re.x+1,re.y)&&check(re.x,re.y-1))re.d=2; 71 else if(check(re.x+1,re.y))re.d=1,re.y--; 72 else if(check(re.x,re.y-1))re.d=3,re.x++; 73 else re.d=2; 74 } 75 return MP(re,abs(*it-u.x)); 76 } 77 bool judge(rec u) 78 { 79 rec re=u; 80 do 81 { 82 pair<rec,int> cur=dfs(u); 83 ans+=cur.second; 84 switch(cur.first.d) 85 { 86 case 1:if(u.d==3)return 0;break; 87 case 2:if(u.d==4)return 0;break; 88 case 3:if(u.d==1)return 0;break; 89 case 4:if(u.d==2)return 0;break; 90 } 91 u=cur.first; 92 }while(!same(re,u)); 93 return 1; 94 } 95 96 signed main() 97 { 98 // freopen("in.txt","r",stdin); 99 100 cin>>n>>m>>k; 101 for(int i=0;i<=m+1;i++)add(0,i),add(n+1,i); 102 for(int i=1;i<=n;i++) add(i,0),add(i,m+1); 103 int a,b; 104 for(int i=1;i<=k;i++) 105 { 106 cin>>a>>b; 107 add(a,b); 108 } 109 int f; 110 cin>>xs>>ys>>te; 111 if(te[0]=='N') 112 { 113 if(te[1]=='E')f=2; 114 else f=1;//W 115 } 116 else//S 117 { 118 if(te[1]=='E')f=3; 119 else f=4;//W 120 } 121 rec st={xs,ys,f}; 122 st=dfs(st).first; 123 if(!judge(st))//判断第一次反向 124 { 125 ans--; 126 switch(st.d) 127 { 128 case 1:st.d=3;break; 129 case 2:st.d=4;break; 130 case 3:st.d=1;break; 131 case 4:st.d=2;break; 132 } 133 judge(st); 134 } 135 cerr<<ans<<endl; 136 cout<<ans<<endl; 137 }
波澜前,面不惊。