方方正正 | ||||||
| ||||||
Description | ||||||
一个r行c列的矩阵里的所有元素都为0或1,给出这个矩阵每一行的和以及每一列的和,那么是否存在这样一个矩阵满足条件呢,如果存在任意一个满足条件的矩阵则输出YES,如果不存在则输出NO? | ||||||
Input | ||||||
每组测试数据第一行包含两个整数r,c,表示矩阵的行数和列数。 第二行包含r个32位无符号数,表示矩阵每行的和。 第三行包含c个32位无符号数,表示矩阵每列的和。 (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;
}