题意很简单,给你一个n*m的矩阵,现在问你这个矩阵能否变为标准矩阵(即数字从小到大),如果能最少需要几步呢?
其实是个赤果果的水题。记得暑假安叔也出过一个类似的题目,那个好像是在codeforces上面吧。
以前我不太理解为什么是这样子做的,现在完全理解了。
对于给定的矩阵,我们可以先不顾其他的,先把任意一列和任意一行放在规定的位置,然后对其他的数进行判断,如果存在不在规定位置的数字,那么这个矩阵就是不合法的;否则这个举证就是合法的。
为什么这么做是对的呢?? 其实我们可以这样来理解。假设当前我们已经任意放好了一列和一行,但是还有其他的位置的数字不能对应相等,那么为了使另外的位置的数字对应相等,我们必须另外交换某一些列或者某一些行,而这些位置是我们本来就已经排列还的,那么我们本来排列好的位置又错位了,等于是拆东墙补西墙,所以就不可能把正确的矩阵排列出来。其实简而言之也就是行列的交换顺序在二维的情况下是可逆等价的(好像这样说不太合适,但是我也不知道怎么说明白)。正是由于这个性质,我们根据贪心的交换法则得到的解就一定是最优解了。
好好理解吧就是这样,水题,我就不多说了,直接排列好第一行和第一列,后面直接验证就好了。
#include <iostream> #include <cstdio> #include <cstring> #define maxn 330 using namespace std; int a[maxn][maxn],n,m,k,ans,x1,y1; void swapl(int y1,int y2) { for (int i=1; i<=n; i++) swap(a[i][y1],a[i][y2]); } void swapc(int x1,int x2) { for (int i=1; i<=m; i++) swap(a[x1][i],a[x2][i]); } bool match() { x1=y1=ans=0; for (int i=1; i<=n; i++) for (int j=1; j<=m; j++) if (a[i][j]==1) { x1=i,y1=j; break; } if (x1==0 || y1==0) return false; if (x1!=1) swapc(x1,1),ans++; if (y1!=1) swapl(y1,1),ans++; for (int i=2; i<=m; i++) { k=0; for (int j=i; j<=m; j++) if (a[1][j]==i) { k=j;break; } if (k==0) return false; if (k!=i) swapl(k,i),ans++; } for (int i=1; i<=n; i++) { k=0; for (int j=i; j<=n; j++) if (a[j][1]==i*m-m+1) { k=j;break; } if (k==0) return false; if (k!=i) swapc(k,i),ans++; } k=1; for (int i=1; i<=n; i++) for (int j=1; j<=m; j++) if (a[i][j]!=k++) return false; return true; } int main() { while (scanf("%d%d",&n,&m)!=EOF) { for (int i=1; i<=n; i++) for (int j=1; j<=m; j++) scanf("%d",&a[i][j]); if (match()) printf("%d ",ans); else printf("* "); } return 0; }