NOIP 2003 传染病控制 解题报告
这题总算是弄好了,大致思路还是简单,我不贴思路了,贴另一个收获,如下,看下面两段代码:
#include <stdio.h>
#include <stdlib.h>
int map[300][300];
int count[300];
int time[300];
int ans, tot;
int n, p;
void maketree(int k)
{
int i;
int j, l;
for(i = 0; i < count[k]; i++){
j = map[k][i];
for(l = 0; l < count[j]; l++){
if(map[j][l] == k){
break;
}
}
map[j][l] = map[j][--count[j]];
maketree(j);
}
}
int use;
void srch(int now)
{
int i, j;
int get = 0;
if(tot > ans){
return;
}
for(i = 0; i < n; i++){ //接下来要传染的
if(time[i] == now){
for(j = 0; j < count[i]; j++){
time[map[i][j]] = now + 1;
get = 1;
tot++;
use++;
}
}
}
tot--;
use++;
for(i = 0; i < n; i++){ //枚举断开哪一个路径
if(time[i] == now + 1){
time[i] = 0; //取消枚举那个路径
srch(now + 1);
time[i] = now + 1;
}
}
tot++;
use++;
for(i = 0; i < n; i++){
if(time[i] == now + 1){
time[i] = 0;
tot--;
use++;
}
}
if(!get && ans > tot){
ans = tot;
}
}
int main(int argc, char **argv)
{
int i;
int a, b;
scanf("%d%d", &n, &p);
for(i = 0; i < p; i++){
scanf("%d%d", &a, &b);
a--, b--;
map[a][count[a]++] = b;
map[b][count[b]++] = a;
}
maketree(0);
time[0] = 1;
ans = 0xFFFFFFF, tot = 1;
srch(1);
// printf("%d\n", ans);
printf("%d\n", use);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int map[300][300];
int count[300];
int time[300];
int ans, tot;
int n, p;
void maketree(int k)
{
int i;
int j, l;
for(i = 0; i < count[k]; i++){
j = map[k][i];
for(l = 0; l < count[j]; l++){
if(map[j][l] == k){
break;
}
}
map[j][l] = map[j][--count[j]];
maketree(j);
}
}
int use;
void srch(int now)
{
int i, j;
int get = 0;
if(tot > ans){
return;
}
for(i = 0; i < n; i++){ //接下来要传染的
if(time[i] == now){
tot++;
use++;
}
}
for(i = 0; i < n; i++){ //接下来要传染的
if(time[i] == now){
for(j = 0; j < count[i]; j++){
time[map[i][j]] = now + 1;
get = 1;
}
}
}
for(i = 0; i < n; i++){ //枚举断开哪一个路径
if(time[i] == now + 1){
time[i] = 0; //取消枚举那个路径
srch(now + 1);
time[i] = now + 1;
}
}
for(i = 0; i < n; i++){
if(time[i] == now + 1){
time[i] = 0;
}
}
if(!get && ans > tot){
ans = tot;
}
for(i = 0; i < n; i++){
if(time[i] == now){
tot--;
use++;
}
}
}
int main(int argc, char **argv)
{
int i;
int a, b;
scanf("%d%d", &n, &p);
for(i = 0; i < p; i++){
scanf("%d%d", &a, &b);
a--, b--;
map[a][count[a]++] = b;
map[b][count[b]++] = a;
}
maketree(0);
time[0] = 1;
ans = 0xFFFFFFF, tot = 0;
srch(1);
// printf("%d\n", ans);
printf("%d\n", use);
return 0;
}
这两段代码思路完全相同,只是一个先统计层数为now+1的个数,另一个统计now的个数,但是两端代码分数截然不同,第一个AC,第二个70分(其实都不能提交,我用的是调试代码),琢磨了我好久,这是怎么导致的,后来用了use来统计所有tot改变的次数,结果发现第一个代码在第一个数据比第二个代码的计算次数多10^2,那不超时才怪呢,后来仔细想才找到原因,比如srch(now)这一层,如果是第一种代码的话就直接计算now + 1这一层,然后再srch(now + 1)计算now + 2那一层,但是第二种代码在srch(now)先计算now这一层,然后再计算srch(now + 1),但是now + 1那一层的个数是固定的,但是在第二种代码中要反复计算很多次。在now层的时候就可以确定now+1层的个数,那么只计算一次就够了,学到了东西啊!!!
在最大匹配的代码里我也发现类似的问题,如果在最大匹配中用memset不超时,但是不用这个就会超时,好死心饿。。
浙公网安备 33010602011771号