Google Code Jam 2009 Round2 A (脑洞题)

Problem A. Crazy Rows

This contest is open for practice. You can try every problem as many times as you like, though we won't keep track of which problems you solve. Read theQuick-Start Guide to get started.
Small input
6 points
 
 
Large input
10 points
 
Judge's response for last submission: Correct.

Problem

You are given an N x N matrix with 0 and 1 values. You can swap any twoadjacent rows of the matrix.

Your goal is to have all the 1 values in the matrix below or on the main diagonal. That is, for each X where 1 ≤ X ≤ N, there must be no 1 values in row X that are to the right of column X.

Return the minimum number of row swaps you need to achieve the goal.

Input

The first line of input gives the number of cases, T. T test cases follow.
The first line of each test case has one integer, N. Each of the nextN lines contains N characters. Each character is either 0 or 1.

Output

For each test case, output

Case #X: K
where X is the test case number, starting from 1, and K is the minimum number of row swaps needed to have all the 1 values in the matrix below or on the main diagonal.

You are guaranteed that there is a solution for each test case.

Limits

1 ≤ T ≤ 60

Small dataset

1 ≤ N ≤ 8

Large dataset

1 ≤ N ≤ 40

Sample


Input
 

Output
 
3
2
10
11
3
001
100
010
4
1110
1100
1100
1000
Case #1: 0
Case #2: 2
Case #3: 4


题目大意:

    输入一个N*N的只有0和1的矩阵,每次可以交换相邻的两行,求把矩阵转化成主对角线上方的元素都是0最小的交换次数。


解题思路:

    首先,对于矩阵的每一行我们只关心最右边的1的位置,所以需要先预处理出每一行最右边一行的1的位置。

    由于每次只能交换相邻的两行,所以要想步数最少定是用类似于冒泡排序的方法。先通过交换确定最上面一行(先确定最下面一行也可以),再确定第二行,再第三行……

    对于每一行的确定,我们只要从这一行往下寻找第一个移动到这里后不会超过对角线的行就可以保证步数最小。


附Correct代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
//#define LOCAL_TEST

const int maxn=40+3;
int N;
char land[maxn][maxn];//矩阵
int a[maxn];//每一行最后一个1出现的位置

int main()
{
#ifndef LOCAL_TEST
    freopen("/Users/xuehao/Downloads/A-large-practice.in","r",stdin);
    freopen("/Users/xuehao/Documents/s1/s1/out","w",stdout);
#endif

    int T;
    scanf("%d",&T);
    for(int tt=1;tt<=T;++tt)
    {
        int ans=0;
        scanf("%d",&N);
        for(int i=0;i<N;++i)
        {
            scanf("%s",land[i]);
            a[i]=-1;//如果没有1,则令最后一个1的位置为-1
            for(int j=0;j<N;++j)
                if(land[i][j]=='1')
                    a[i]=j;
        }
        for(int i=0;i<N;++i)
        {
            int pos=-1;
            for(int j=i;j<N;++j)
                if(a[j]<=i)//第一个1不超过位置i的对角线的行
                {
                    pos=j;
                    break;
                }
            for(int j=pos;j>i;--j)//交换
            {
                swap(a[j],a[j-1]);
                ++ans;
            }
        }
        printf("Case #%d: %d\n",tt,ans);
    }
    
#ifndef LOCAL_TEST
    fclose(stdin);
    fclose(stdout);
#endif
    
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值