UVA11625_Lines of Containers

题意很简单,给你一个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\n",ans);
            else printf("*\n");
    }
    return 0;
}

 

posted @ 2013-11-15 21:16  092000  阅读(387)  评论(0编辑  收藏  举报