Educational Codeforces Round 89 (Rated for Div. 2) C Palindromic Paths
题目链接:Palindromic Paths
题意:
给你一个n行m列的矩阵,这个矩阵被0或者1所填充,你需要从点(1,1)走到点(n,m)。这个时候会有很多路径,每一条路径对应一个01串,你可以改变这个矩阵中某些位置的值,你需要保证改变之后每一条路径串都是回文串。
最后输出你最少需要改变多少位置
题解:
因为你要保证每一条路径都是回文路径,那么如下面这组样例:
3 5
1 0 1 0 0
1 1 1 1 0
0 0 1 0 0
起点位置(1,1)的值是1但是终点位置(n,m)的值是0,但是在一条路径串上面这两个点必须是串的起点和终点,那么如果这条串要变成回文串,那么这两个位置的值就必须相等。其他位置也是一样,比如路径串的第二个位置的值需要和串的倒数第二个位置的值相等。
那么我们只需要让这个串的第二步走的所有位置的值和倒数第二步走的所有位置的值相等就行。例如上面的例子:
第一步:我们需要把(1,1)和(n,m)的值变成相同,共有1个0,1个1,那么都变成1也行,变成0也行
第二步:串的第一个位置是(1,1),那么第二步可以走到(1,2)和(2,1)。串的倒数第一个位置是(n,m),那么倒数第二步可以走到(n-1,m)和(n,m-1)这两个位置
我们发现这四个位置共有3个0,1个1。因为我们必须要把它们变成一样的且题目要求输出最小改变的位置数量,那么我们可以让1变成0就可以了
第三步:和上面差不多
代码实现我用了两个队列r1和r2,r1是从起点(1,1)开始进行bfs,r2是从终点(n,m)开始bfs遍历。每次r1和r2都向前遍历一个层次就统计一样0和1的个数。判断一下是0变1还是1变0
我们要注意这个遍历过程要有一个终止位置,比如下面这组样例
2 2
1 1
0 1
对于(1,2)位置和(2,1)位置我们就不需要要求它们必须相同,因为这个串的长度肯定是一个奇数,那么不管串中间那个位置是0还是1都不会造成影响,所以就不用管
所以再从起点和终点两个位置同时进行遍历只需要ans次,ans计算如下:
1 int num=(m-1)+(n-1),ans; 2 num%2==0?ans=num/2-1:ans=num/2;
代码:
1 #include<stdio.h> 2 #include<algorithm> 3 #include<iostream> 4 #include<string> 5 #include<queue> 6 #include<deque> 7 #include<string.h> 8 #include<map> 9 #include <iostream> 10 #include <math.h> 11 using namespace std; 12 typedef long long ll; 13 const int maxn=35; 14 struct shudui 15 { 16 int x,y,val,type; 17 } str1,str2; 18 int w[maxn][maxn],n,m,sum,vis[maxn][maxn]; 19 int p[2][2]= 20 { 21 {0,1}, 22 {1,0} 23 }; 24 queue<shudui>r1,r2; 25 void bfs(int ci) 26 { 27 int zero,one; 28 for(int k=0; k<ci; ++k) 29 { 30 zero=one=0; 31 while(!r1.empty()) 32 { 33 str1=r1.front(); 34 if(str1.type==k) 35 { 36 r1.pop(); 37 for(int i=0; i<2; ++i) 38 { 39 int xx=str1.x+p[i][0]; 40 int yy=str1.y+p[i][1]; 41 if(xx>=1 && xx<=n && yy>=1 && yy<=m && vis[xx][yy]==0) 42 { 43 //printf("***\n"); 44 str2.x=xx; 45 str2.y=yy; 46 str2.type=str1.type+1; 47 str2.val=w[xx][yy]; 48 //printf("%d %d**\n",xx,yy); 49 vis[xx][yy]=1; 50 if(w[xx][yy]) 51 { 52 one++; 53 } 54 else zero++; 55 r1.push(str2); 56 } 57 } 58 } 59 else break; 60 } 61 62 while(!r2.empty()) 63 { 64 str1=r2.front(); 65 if(str1.type==k) 66 { 67 r2.pop(); 68 for(int i=0; i<2; ++i) 69 { 70 int xx=str1.x-p[i][0]; 71 int yy=str1.y-p[i][1]; 72 if(xx>=1 && xx<=n && yy>=1 && yy<=m && vis[xx][yy]==0) 73 { 74 75 str2.x=xx; 76 str2.y=yy; 77 str2.type=str1.type+1; 78 str2.val=w[xx][yy]; 79 //printf("%d %d**\n",xx,yy); 80 vis[xx][yy]=1; 81 if(w[xx][yy]) 82 { 83 one++; 84 } 85 else zero++; 86 r2.push(str2); 87 } 88 } 89 } 90 else break; 91 } 92 //printf("%d %d\n---------------\n\n\n",zero,one); 93 sum+=min(zero,one); 94 } 95 // if(m%2) 96 // { 97 // zero=one=0; 98 // while(!r1.empty()) 99 // { 100 // if(r1.front().val) 101 // one++; 102 // else zero++; 103 // r1.pop(); 104 // } 105 // sum+=min(zero,one); 106 // } 107 } 108 int main() 109 { 110 int t; 111 scanf("%d",&t); 112 while(t--) 113 { 114 while(!r1.empty()) r1.pop(); 115 while(!r2.empty()) r2.pop(); 116 memset(vis,0,sizeof(vis)); 117 memset(w,0,sizeof(w)); 118 sum=0; 119 scanf("%d%d",&n,&m); 120 for(int i=1; i<=n; ++i) 121 { 122 for(int j=1; j<=m; ++j) 123 { 124 scanf("%d",&w[i][j]); 125 } 126 } 127 // if(n==m && n==2) 128 // { 129 // printf("0\n"); 130 // continue; 131 // } 132 str1.type=0; 133 str1.val=w[1][1]; 134 vis[1][1]=vis[n][m]=1; 135 str1.x=str1.y=1; 136 r1.push(str1); 137 str1.x=n; 138 str1.y=m; 139 str1.val=w[n][m]; 140 r2.push(str1); 141 int num=(m-1)+(n-1),ans; 142 num%2==0?ans=num/2-1:ans=num/2; 143 bfs(ans); 144 if(w[1][1]!=w[n][m]) sum++; 145 printf("%d\n",sum); 146 } 147 return 0; 148 }