# 芯片测试问题

3
1 0 1
0 1 0
1 0 1

1 3

## 生成数据

"蓝桥杯"练习系统有原题，然而贫穷限制了我。

void getrand(int num) { //num为样本大小
int rightcnt = num / 2 + 1; //保证一半以上好芯片
int wrongcnt = num - rightcnt;
srand((unsigned int)time(0)); //随机种子
int r = rand() % wrongcnt;
rightcnt += r; //随机好坏数量
wrongcnt -= r;
int ans[maxn] = { 0 };  //记录芯片好坏
while (rightcnt--) {  //随机好芯片编号
int idx = rand() % num + 1;
if (ans[idx]) {
rightcnt++;
continue;
}
ans[idx] = 1;
}
for (int i = 1; i <= num; i++)
if (ans[i])
printf("%d ", i);
FILE* fp = fopen("in.txt", "w+");
if (!fp) {
printf("无法打开文件\n");
exit(0);
}
fprintf(fp, "%d\n", num);
for (int i = 1; i <= num; i++) {
if (ans[i])  //i是好的，输出ans
for (int j = 1; j <= num; j++)
fprintf(fp, "%d ", ans[j]);
else  //i是坏的，随机
for (int j = 1; j <= num; j++)
fprintf(fp, "%d ", rand() % 2);
fprintf(fp, "\n");
}
fclose(fp);
}

## 暴力

void method1() { //O(n^2)
int cnt[maxn] = { 0 };
DWORD start_time = GetTickCount();
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (m[i][j] && i != j)
cnt[j]++;
int half = n >> 1;
FILE* f = fopen("out1.txt", "w+");
if (!f) {
printf("无法打开文件\n");
exit(0);
}
for (int i = 1; i <= n; i++)
if (cnt[i] >= half)
fprintf(f,"%d ", i);
DWORD end_time = GetTickCount();
fprintf(f, "\n用时%dms", end_time - start_time);
fclose(f);
}

## 分治

1. 两好（设 i i 组）
2. 一好一坏（设 j j 组）
3. 两坏（设 k k 组）

void method2() { //O(n)
list<int>l;  //删除操作多,用list
list<int>::iterator it, ij;
for (int i = 1; i <= n; i++)l.push_back(i);
DWORD start_time = GetTickCount();
while (l.size() > 3) {
for (it = l.begin(); it != l.end(); ) {
ij = it;
it++;
if (it == l.end()) { //奇数轮空
int cnt = 0;
for (it = l.begin(); it != l.end(); it++)
if (m[*it][*ij])
cnt++;
if (cnt < l.size() / 2) //超过一半坏，弃之
l.erase(ij);
break;
}
else { //偶数
if (m[*it][*ij] && m[*ij][*it]) //两好则保留一个
it=l.erase(it);
else {  //否则全弃
it = l.erase(it);
it = l.erase(ij);
}
}
}
}
int right;
if (l.size() == 3) {
it = l.begin();
ij = it++;
if (m[*it][*ij] && m[*ij][*it])right = *it;
else right = *(++it);
}
else right = l.front();
FILE* f = fopen("out2.txt", "w+");
if (!f) {
printf("无法打开文件\n");
exit(0);
}
for (int i = 1; i <= n; i++)
if (m[right][i])
fprintf(f, "%d ", i);
DWORD end_time = GetTickCount();
fprintf(f, "\n用时%dms", end_time - start_time);
fclose(f);
}

## 源码

#include<bits/stdc++.h>
#include<Windows.h>
using namespace std;
const int maxn = 10004;
int n, m[maxn][maxn];
void getrand(int num) {
int rightcnt = num / 2 + 1; //保证一半以上好芯片
int wrongcnt = num - rightcnt;
srand((unsigned int)time(0)); //随机种子
int r = rand() % wrongcnt;
rightcnt += r; //随机好坏数量
wrongcnt -= r;
int ans[maxn] = { 0 };
while (rightcnt--) {
int idx = rand() % num + 1;
if (ans[idx]) {
rightcnt++;
continue;
}
ans[idx] = 1;
}
for (int i = 1; i <= num; i++)
if (ans[i])
printf("%d ", i);
FILE* fp = fopen("in.txt", "w+");
if (!fp) {
printf("无法打开文件\n");
exit(0);
}
fprintf(fp, "%d\n", num);
for (int i = 1; i <= num; i++) {
if (ans[i])  //i是好的，输出ans
for (int j = 1; j <= num; j++)
fprintf(fp, "%d ", ans[j]);
else  //i是坏的，随机
for (int j = 1; j <= num; j++)
fprintf(fp, "%d ", rand() % 2);
fprintf(fp, "\n");
}
fclose(fp);
}
void method1() { //O(n^2)
int cnt[maxn] = { 0 };
DWORD start_time = GetTickCount();
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (m[i][j] && i != j)
cnt[j]++;
int half = n >> 1;
FILE* f = fopen("out1.txt", "w+");
if (!f) {
printf("无法打开文件\n");
exit(0);
}
for (int i = 1; i <= n; i++)
if (cnt[i] >= half)
fprintf(f,"%d ", i);
DWORD end_time = GetTickCount();
fprintf(f, "\n用时%dms", end_time - start_time);
fclose(f);
}
void method2() { //O(n)
list<int>l;
list<int>::iterator it, ij;
for (int i = 1; i <= n; i++)l.push_back(i);
DWORD start_time = GetTickCount();
while (l.size() > 3) {
for (it = l.begin(); it != l.end(); ) {
ij = it;
it++;
if (it == l.end()) { //奇数轮空
int cnt = 0;
for (it = l.begin(); it != l.end(); it++)
if (m[*it][*ij])
cnt++;
if (cnt < l.size() / 2) //超过一半坏，弃之
l.erase(ij);
break;
}
else { //偶数
if (m[*it][*ij] && m[*ij][*it]) //两好则保留一个
it=l.erase(it);
else {  //否则全弃
it = l.erase(it);
it = l.erase(ij);
}
}
}
}
int right;
if (l.size() == 3) {
it = l.begin();
ij = it++;
if (m[*it][*ij] && m[*ij][*it])right = *it;
else right = *(++it);
}
else right = l.front();
FILE* f = fopen("out2.txt", "w+");
if (!f) {
printf("无法打开文件\n");
exit(0);
}
for (int i = 1; i <= n; i++)
if (m[right][i])
fprintf(f, "%d ", i);
DWORD end_time = GetTickCount();
fprintf(f, "\n用时%dms", end_time - start_time);
fclose(f);
}
int main() {
getrand(1000);
FILE* fp = fopen("in.txt", "r");
if (!fp) {
printf("无法打开文件\n");
exit(0);
}
fscanf(fp, "%d", &n);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
fscanf(fp, "%d", &m[i][j]);
fclose(fp);
method1();
method2();
return 0;
}

04-14
12-11 1万+

03-03 2698
02-27 1324
04-13 346
03-24 1911
12-06 362
05-30 365