Codeforces 985B 题解 - 枚举,统计
题意
有\(n\)个开关和\(m\)盏灯,给定一个矩阵\(a(a_{i,j}\in [0,1])\),若\(a_{i,j}=1\)则说明开关\(i\)与第\(j\)盏灯连接.初始时所有灯都是关闭的.按下某开关后,所有与这个开关连接的灯将会打开,已经打开的不会关闭.
现在你需要去掉一个开关,使得按下剩余\(n-1\)个开关后,所有灯都可以打开.若存在方案,则输出YES
,否则输出NO
.
题解
直观的想法为,枚举去掉的开关\(i\),然后枚举每个与开关\(i\)相连的灯\(j\),若存在一个\(j\)只能靠开关\(i\)打开(即矩阵第\(j\)列只有第\(i\)行为\(1\)),那么说明\(i\)不能去掉.
但是这是\(\mathcal O(n^3)\)的.
优化很简单,我们可以发现我们枚举了很多次某一列.直接记录\(cnt_j\)表示第\(j\)列中\(1\)的个数,也即第\(j\)盏灯连接这的开关数.
在判断时,直接判断\(cnt_j\)是否等于\(1\)即可.
时间复杂度\(\mathcal O(n^2)\)
代码
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cctype>
using namespace std;
const int N = 2005;
int n, m, cnt[N];
char a[N][N];
int main(){
scanf("%d%d", &n, &m);
for (register int i = 1; i <= n; ++i)
for (register int j = 1; j <= m; ++j)
while (!isdigit(a[i][j] = getchar()));
for (register int i = 1; i <= n; ++i)
for (register int j = 1; j <= m; ++j)
cnt[j] += a[i][j] ^ '0'; // 统计cnt
for (register int i = 1; i <= n; ++i){
register bool bo = true;
for (register int j = 1; j <= m; ++j)
if (a[i][j] == '1' && cnt[j] == 1) bo = false; // 直接判断即可
if (bo) return printf("YES"), 0;
}
return printf("NO"), 0;
}