EC复建补题,补掉北京赛场上卡的两个题。 Liaoning Ship’s Voyage 和 Puzzle Game
Liaoning Ship’s Voyage
一个只有20×20的矩阵上面进行bfs求最短路,为了增加难度,上面随便画一个三角形,被称作百慕大三角,八联通的走,不能进入三角形,问最短路。
直接bfs,判断可不可行的时候用,暴力将八联通线段拆成(X)段,看点是否在三角形内即可。
亲测X = 100就行。
1 #include <bits/stdc++.h> 2 const long long mod = 1e9+7; 3 const double eps = 1e-8; 4 #define inf 0x3f3f3f3f 5 using namespace std; 6 typedef pair<double,double> pdd; 7 pair <double,double>a,b,c; 8 int vis[50][50],n; 9 char ma[50][50]; 10 int dx[] = {1,-1,0,0,-1,-1,1,1}; 11 int dy[] = {0,0,1,-1,1,-1,1,-1}; 12 struct P{ 13 int x,y,step; 14 P(){} 15 P(int x,int y,int step):x(x),y(y),step(step){} 16 }; 17 inline double cross(pdd a,pdd b){ 18 return a.first*b.second - a.second *b.first; 19 } 20 inline int sgn(double x){ 21 if (x > eps) return 1; 22 else if (x < -eps ) return -1; 23 return 0; 24 } 25 inline bool check(double xx,double yy){ 26 pdd V1 = make_pair(-xx+a.first,-yy+a.second); 27 pdd V2 = make_pair(-xx+b.first,-yy+b.second); 28 pdd V3 = make_pair(-xx+c.first,-yy+c.second); 29 double res1 = cross(V1,V2); 30 double res2 = cross(V2,V3); 31 double res3 = cross(V3,V1); 32 if (sgn(res1)>0&&sgn(res2) > 0 && sgn(res3) > 0) return false; 33 else if (sgn(res1)<0&&sgn(res2) < 0 && sgn(res3) < 0) return false; 34 return true; 35 } 36 int main() 37 { 38 while (scanf("%d",&n)!=EOF){ 39 scanf("%lf%lf%lf%lf%lf%lf",&a.first,&a.second,&b.first,&b.second,&c.first,&c.second); 40 getchar(); 41 memset(vis,0,sizeof(vis)); 42 for (int i = n - 1 ; i >=0 ; i--){ 43 for (int j = 0 ; j < n ;j++){ 44 scanf("%c",&ma[j][i]); 45 } 46 getchar(); 47 } 48 queue<P> que; 49 if (ma[0][0] == '#') {puts("-1");continue;} 50 vis[0][0] = 1; 51 que.push(P(0,0,0)); 52 int flag = 0; 53 while (!que.empty()){ 54 P now = que.front(); 55 que.pop(); 56 if (now.x == n - 1 && now.y == n-1){ 57 flag = 1;printf("%d\n",now.step);break; 58 } 59 for (int i = 0 ; i < 8 ; i++){ 60 int xx = now.x + dx[i]; 61 int yy = now.y + dy[i]; 62 if (xx < 0 || yy < 0 ||xx >=n || yy >=n) continue; 63 if (ma[xx][yy] =='#') continue; 64 double tmpx = now.x,tmpy = now.y; 65 double addx = 1.0 * dx[i]/100.0; 66 double addy = 1.0 * dy[i]/100.0; 67 int flag2 = 1; 68 for (int j = 1;j <=100; j++){ 69 if (check(tmpx,tmpy) == 0){ 70 flag2 = 0;break; 71 } 72 tmpx +=addx;tmpy +=addy; 73 } 74 if (flag2 ==0)continue; 75 if (vis[xx][yy] ==0){ 76 P nex = P(xx,yy,now.step+1); 77 que.push(nex); 78 vis[xx][yy] = 1; 79 } 80 } 81 } 82 if (flag == 0) puts("-1"); 83 } 84 return 0; 85 }
Puzzle Game
最多更改矩阵中的一个点变为x,最小化,最大矩阵和。
这个 暴力算法是枚举 更改哪个点,然后求最大矩阵和。
现在可以优化一下,更改这个点之后的答案,分为两种情况,不包含这个点的最大子矩阵ans1,以及包含这个点的最大子矩阵ans2 - a[i][j] + x。
包含这个点的最大子矩阵怎么算呢?
这算是一个放缩吧,
如果max为包含这个点的矩阵和,那么 答案显然为ans2 = max
如果max不是呢?肯定存在别的矩阵为max,那么ans2是谁多大也就没有意义了,并且max - a[i][j] + x 是显然小于 max的(因为我们前面continue掉了)。
1 #include <bits/stdc++.h> 2 #define inf 0x3f3f3f3f 3 using namespace std; 4 int ans[5][200]; 5 int a[200][200]; 6 int sum[200]; 7 int main() 8 { 9 int n,m,tmp; 10 //freopen("in.txt","r",stdin); 11 while (cin >> n >> m >> tmp){ 12 memset(a,0,sizeof(a)); 13 for (int i = 1 ; i <= n ; i++){ 14 for (int j = 1; j <= m ; j++){ 15 scanf("%d",&a[i][j]); 16 } 17 } 18 for (int j = 0 ; j<=180 ; j++) 19 ans[0][j] = ans[1][j] = ans[2][j] = ans[3][j] = -inf; 20 21 for (int i = 1 ; i <=n; i++){ 22 memset(sum,0,sizeof(sum)); 23 for (int j = i ; j<=n; j++){ 24 for (int t = 1; t <= m ; t++) sum[t] += a[j][t]; 25 int tsum = 0; 26 int la = 0; 27 int tans = -inf; 28 for (int k = 1; k <= m; k++){ 29 while (tsum < 0) tsum -= sum[la],la++; 30 tsum += sum[k]; 31 tans = max(tans,tsum); 32 } 33 ans[0][i] = max(ans[0][i],tans); 34 ans[1][j] = max(ans[1][j],tans); 35 } 36 } 37 for (int i = 1 ; i <=m; i++){ 38 memset(sum,0,sizeof(sum)); 39 for (int j = i ; j<=m; j++){ 40 for (int t = 1; t <= n ; t++) sum[t] += a[t][j]; 41 int tsum = 0; 42 int la = 0; 43 int tans = -inf; 44 for (int k = 1; k <= n; k++){ 45 while (tsum < 0) tsum -= sum[la],la++; 46 tsum += sum[k]; 47 tans = max(tans,tsum); 48 } 49 ans[2][i] = max(ans[2][i],tans); 50 ans[3][j] = max(ans[3][j],tans); 51 } 52 } 53 for (int i = n ; i >=1 ; i--) ans[0][i] = max(ans[0][i],ans[0][i+1]); 54 for (int i = m ; i >=1 ; i--) ans[2][i] = max(ans[2][i],ans[2][i+1]); 55 for (int i = 1 ; i <=n ; i++) ans[1][i] = max(ans[1][i],ans[1][i-1]); 56 for (int i = 1 ; i <=m ; i++) ans[3][i] = max(ans[3][i],ans[3][i-1]); 57 int res = ans[0][1]; 58 for (int i = 1 ; i <= n ;i++){ 59 for (int j = 1 ; j <= m ; j++){ 60 if (a[i][j] < tmp) continue; 61 int tres = ans[0][1] - a[i][j] + tmp; 62 tres = max(tres,ans[0][i+1]); 63 tres = max(tres,ans[1][i-1]); 64 tres = max(tres,ans[2][j+1]); 65 tres = max(tres,ans[3][j-1]); 66 //cout << tres <<" " << i <<" " << j << endl; 67 //cout << ans[0][i+1] <<" " <<ans[1][i-1] <<" " << ans[2][j+1] <<" "<< ans[3][j-1] << endl; 68 res = min(res,tres); 69 } 70 } 71 cout << res << endl; 72 } 73 74 }