方方正正

方方正正
Time Limit: 1000 MSMemory Limit: 32768 K
Total Submit: 10(7 users)Total Accepted: 5(5 users)Rating: Special Judge: No
Description

一个rc列的矩阵里的所有元素都为01,给出这个矩阵每一行的和以及每一列的和,那么是否存在这样一个矩阵满足条件呢,如果存在任意一个满足条件的矩阵则输出YES,如果不存在则输出NO

Input

(此行删除)第一行为一个正整数T(T <= 100),表示测试样例的组数。

每组测试数据第一行包含两个整数r,c,表示矩阵的行数和列数。

第二行包含r32位无符号数,表示矩阵每行的和。

第三行包含c32位无符号数,表示矩阵每列的和。

(1 <= r,c <= 100000)

处理到文件结束

Output
如果存在这样的一个01矩阵,输出YES,否则输出NO
Sample Input


1 1

0

1

1 1

1

1


Sample Output

NO

YES

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<queue>
#include<algorithm>
using namespace std;
int main(){
    int m,n;
    int na,nb;
    int ma,mb;
    int a;
    int sa,sb;
    while(~scanf("%d %d",&m,&n)){
        na=0;nb=0;
        ma=0;mb=0;
        sa=0;sb=0;
        while(m--){
            scanf("%d",&a);
            if(a){
                na++;
                sa+=a;
            }
            if(a>ma)
                ma=a;
        }
        while(n--){
            scanf("%d",&a);
            if(a){
                nb++;
                sb+=a;
            }
            if(a>mb)
                mb=a;
        }
        if(sa!=sb||ma>nb||mb>na)
            printf("NO\n");
        else
            printf("YES\n");
    }
    return 0;
}


标准题解

首先需要判断行和列的总和是否相等,因为它们都应该是整个矩阵的所有元素之和。如果他们不相等则这个矩阵肯定不存在。

这道题的贪心策略是,把列和从大到小枚举,对每个列和,按行和从大到小的顺序进行选择填上1,然后该行的行和减去1.这种贪心策略之所以有效,是因为这种策略会使各行的行和趋向于平均,尽可能地使行和减为零的情况推迟发生,而行和减为零意味着,当前可选的行数减少1,因此后面的计算可选择方法肯定比这种贪心的策略要少。

#include <stdio.h>
#include <algorithm>
using namespace std;
const int size=100000;				//最大行列数
int a[size],b[size];				//分别保存行和与列和
int main(){
	int r,c,i,j;
	long long s,t;					//枚举时比较的行和与列和总数
	while(scanf("%d%d",&r,&c)==2){//输入整数r,c直到文件结束
		for(i=0,s=0; i<r; i++){
			scanf("%d",&a[i]);		//输入行和
			s+=a[i];					//累加行和
		}
		for(i=0,t=0; i<c; i++){
			scanf("%d",&b[i]);		//输入列和
			t+=b[i];					//累加列和
		}
		if(s!=t){						//如果行和与列和总数不相等
			printf("NO\n");			//则不可能有解
			continue;
		}
		sort(a,a+r);					//行和排序
		sort(b,b+c);					//列和排序
		for(i=j=0,t=s=0; i<c; i++){//从大到小枚举列和
			t+=b[c-i-1];				//当前已枚举的列和总数
			s+=r-j;					//当前可用的行和总数
			while(j<r&&a[j]<i+1){	//如果某行和小于枚举列数
				s-=i+1-a[j];			//把行和总数多算出来的部分减去
				j++;
			}
			if(s<t) break;			//如果可用行和小于当前列和则不可能有解
		}
		printf(i==c?"YES\n":"NO\n");//输出答案
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值