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不超时,但是不用这个就会超时,好死心饿。。