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

posted @ 2011-07-25 21:02  zqynux  阅读(992)  评论(0编辑  收藏  举报