1.题目描述:点击打开链接
2.解题思路:本题利用逆向思维+贪心法解决。因为题目中已经告诉我们一定存在解,因此可以考虑贪心法的使用。这道题的妙处在于答案和初始矩阵是无关的,只和目标矩阵有关。因为不管初始矩阵长什么样,只要操作一样,加上解的存在性,得到的目标矩阵一定是相同的。接下来就是如何寻找操作序列。
假设最后一步操作执行后,我们得到了目标矩阵,由于所有操作都是对一整行或者一整列进行的,因此肯定有一行或者一列全部相同。这样,我们就可以从目标矩阵出发,逆着这个过程寻找,如果发现某一行或者一列全部相同, 那么就把对应的操作入队列,同时把这一行全部置零,本次操作也置零。
注意:本题的扫描顺序比较重要。我们规定从上往下,从左往右依次扫描,这样可以保证某些行或列置零后,剩余的行或列的非零元素依然连续。而且还有一个好处是当整个矩阵都置零后,剩余入队列的操作都是无关操作。
3.代码:
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream> #include<algorithm> #include<cassert> #include<string> #include<sstream> #include<set> #include<vector> #include<stack> #include<map> #include<queue> #include<deque> #include<cstdlib> #include<cstdio> #include<cstring> #include<cmath> #include<ctime> #include<cctype> #include<functional> using namespace std; #define me(s) memset(s,0,sizeof(s)) typedef long long ll; typedef unsigned int uint; typedef unsigned long long ull; typedef pair <int, int> P; const int N=105; int A[N][N]; int x[5*N],y[5*N],s[5*N][2]; int a[5*N]; int n,m; int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&A[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&A[i][j]);//由于目标矩阵才是本题的关键,因此只保存目标矩阵 for(int i=1;i<=m;i++) scanf("%s%d%d",s[i],&x[i],&y[i]); int k=0; while(k<m)//大循环是m个操作是否都找到 { for(int i=1;i<=m;i++) if(x[i]) //x[i]相当于标识符,大于0说明有对应的操作,等于0说明操作已经用过 { if(s[i][0]=='L')//列操作 { int j; for(j=1;j<=n;j++)//从上往下枚举行,看是否连续相等且都是大于0的 if(A[j][x[i]]&&A[j][x[i]]!=y[i])break; if(j>n)//如果连续相等或连续都等于0 { a[k++]=i; for(j=1;j<=n;j++) A[j][x[i]]=0;//将整列置零 x[i]=0; //将操作标识符置零 } } else //行操作同上 { int j; for(j=1;j<=n;j++) if(A[x[i]][j]&&A[x[i]][j]!=y[i])break; if(j>n) { a[k++]=i; for(j=1;j<=n;j++) A[x[i]][j]=0; x[i]=0; } } } } for(int i=k-1;i>=0;i--) printf("%d%c",a[i]," \n"[i==0]); } }