zoukankan      html  css  js  c++  java
  • 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
    ",ans);
                else printf("*
    ");
        }
        return 0;
    }
    如有转载,请注明出处(http://www.cnblogs.com/lochan)
  • 相关阅读:
    转:专题五线程同步——事件构造
    转:专题四线程同步
    转:专题三线程池中的I/O线程
    转:[C# 开发技巧]如何防止程序多次运行
    转:专题二线程池中的工作者线程
    转:专题一线程基础
    C# 设置按钮快捷键
    jmeter链接多台负载机报错
    java读取properties
    使用Runtime.getRuntime().exec()方法的几个陷阱
  • 原文地址:https://www.cnblogs.com/lochan/p/3426090.html
Copyright © 2011-2022 走看看