TOJ4789(深搜回溯)

4789: 传染病控制 分享至QQ空间
时间限制(普通/Java):1000MS/3000MS 内存限制:65536KByte
总提交: 53 测试通过:14
描述

【问题背景】

近来,一种新的传染病肆虐全球。蓬莱国也发现了零星感染者,为防止该病在蓬莱国大范围流行,该国政府决定不惜一切代价控制传染病的蔓延。不幸的是,由于人们尚未完全认识这种传染病,难以准确判别病毒携带者,更没有研制出疫苗以保护易感人群。于是,蓬莱国的疾病控制中心决定采取切断传播途径的方法控制疾病传播。经过 WHO(世界卫生组织)以及全球各国科研部门的努力,这种新兴传染病的传播途径和控制方法已经研究消楚,剩下的任务就是由你协助蓬莱国疾控中心制定一个有效的控制办法。

【问题描述】

研究表明,这种传染病的传播具有两种很特殊的性质;

第一是它的传播途径是树型的,一个人X只可能被某个特定的人Y感染,只要Y不得病,或者是XY之间的传播途径被切断,则X就不会得病。

第二是,这种疾病的传播有周期性,在一个疾病传播周期之内,传染病将只会感染一代患者,而不会再传播给下一代。

这些性质大大减轻了蓬莱国疾病防控的压力,并且他们已经得到了国内部分易感人群的潜在传播途径图(一棵树)。但是,麻烦还没有结束。由于蓬莱国疾控中心人手不够,同时也缺乏强大的技术,以致他们在一个疾病传播周期内,只能设法切断一条传播途径,而没有被控制的传播途径就会引起更多的易感人群被感染(也就是与当前已经被感染的人有传播途径相连,且连接途径没有被切断的人群)。当不可能有健康人被感染时,疾病就中止传播。所以,蓬莱国疾控中心要制定出一个切断传播途径的顺序,以使尽量少的人被感染。

你的程序要针对给定的树,找出合适的切断顺序。

输入

输入格式的第一行是两个整数n(1≤n≤300)和p。接下来p行,每一行有两个整数i和j,表示节点i和j间有边相连(意即,第i人和第j人之间有传播途径相连)。其中节点1是已经被感染的患者。

输出

只有一行,输出总共被感染的人数。

样例输入

7 6
1 2
1 3
2 4
2 5
3 6
3 7

样例输出

3
题解:
这题一拿到手就想到用Dfs来做,N的范围<=300;
对于这题我的想法是 先存边,因为是树,所以我通过本想通过一次Bfs来预处理出每一层的点,因为你要切肯定是要切离根最近的点开始切,这样才能保证答案最优。
处理出每一层的点后,然后通过两次BFS ,第一次标记已经是走过了并且不会被感染,第二次回溯到初始状态。
然后就T了两个点。然后我换了一种写法用DFS些仍然T了两个点,T的是第4个点
10 9
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
输出
1
而我的答案是10000000,说明我的代码没有往下走,因为一开始就切完了,所以我做了一个优化,如果没有点就不需要往下走了,直接比较答案返回,就过了,但是一开始的写法这样优化后还是T了两个,不知道为啥~~

DFS 100分

预处理

void vis_dfs(int x,int dep){ //dep记深度
    son[x] = 1;d[x] = dep; //son标记包括该点的孩子有几个,d数组标记每个点的深度
    deepmax  = max(deepmax,dep); //最大深度,出口
    for(int i = 0; i < edge[x].size(); i++){ //遍历边
        int k = edge[x][i];
        if(!vis[k]){
            vis[k] = 1;
            deep[dep+1].push_back(k);
            vis_dfs(k,dep+1);
            son[x] += son[k]; //回溯的时候更新父节点的孩子书数
        }
    }
}

深搜回溯

void dfs_0(int x){ //没啥好说的
    vis[x] = 0;
    for(int i = 0; i < edge[x].size(); i++){
        int k = edge[x][i];
        if(d[k] > d[x]) //关键是这里,因为给的可以说是无向图,必须要是深度比你大的才能走下去。
            vis[k] = 0,dfs_0(k);
    }
}
void dfs_1(int x){
    vis[x] = 1;
    for(int i = 0; i < edge[x].size(); i++){
        int k = edge[x][i];
        if(d[k] > d[x])
            vis[k] = 1,dfs_1(k);
    }
}

~~

#include
using namespace std;
const int N = 305;
int tree[N],son[N],n,p,vis[N],Min,deepmax,d[N];
vector<int>deep[N],edge[N];
//deep存每个深度的点,edge存边
void vis_dfs(int x,int dep){
    son[x] = 1;d[x] = dep;
    deepmax  = max(deepmax,dep);
    for(int i = 0; i < edge[x].size(); i++){
        int k = edge[x][i];
        if(!vis[k]){
            vis[k] = 1;
            deep[dep+1].push_back(k);
            vis_dfs(k,dep+1);
            son[x] += son[k];
        }
    }
}

void dfs_0(int x){
    vis[x] = 0;
    for(int i = 0; i < edge[x].size(); i++){
        int k = edge[x][i];
        if(d[k] > d[x])
            vis[k] = 0,dfs_0(k);
    }
}

void dfs_1(int x){
    vis[x] = 1;
    for(int i = 0; i < edge[x].size(); i++){
        int k = edge[x][i];
        if(d[k] > d[x])
            vis[k] = 1,dfs_1(k);
    }
}

void dfs(int x,int ans){
    int flag = 0;
    if(x > deepmax){ //当比最大深度还要大的时候,就是出口
        Min = min(Min,n - ans);
        return ;
    }
    for(int i = 0; i < deep[x].size(); i++){
        int k = deep[x][i];
        if(vis[k]){
            flag = 1;
            dfs_0(k);
            dfs(x + 1,ans + son[k]);
            dfs_1(k);
        }
    }
    if(!flag){ //优化,找不到点就直接退出,说明下面几层的点都被切完了,不加会T两个点
        Min = min(Min,n - ans);
        return ;
    }
}

int main(){
    cin >> n >> p;
    for(int i = 0; i < p; i++){
        int x,y;
        cin >> x >> y; //注意是两边都要加,一开始以为是单向的
        edge[x].push_back(y),edge[y].push_back(x);
    }
    vis[1] = 1;Min = 1e9;
    vis_dfs(1,0);
    dfs(1,0);
    printf("%d\n",Min);
}

BFS 80分

我估计是两次bfs里面东西太多了,写的很乱~

#include
using namespace std;
const int N = 305;
vector<int>vec[N],tree[N];
int vis[N],dep,Min,n,p,d[N];

struct node{
    int x,depth;
}now,next;

void vis_bfs(){
    queue<node>q;
    now.x = 1,now.depth = 0;vis[1] = 1;
    q.push(now);
    while(!q.empty()){
        now = q.front();
        dep = max(dep,now.depth);
        d[now.x] = now.depth;
        q.pop();
        for(int i = 0; i < vec[now.x].size(); i++){
            int k = vec[now.x][i];
            if(!vis[k]){
                next.x = k,next.depth = now.depth + 1;
                tree[next.depth].push_back(k);
                vis[k] = 1,q.push(next);
            }
        }
    }
}

void bfs_0(int x){
    int v[N];
    for(int i = 1; i <= n; i++) v[i] = 0;
    queue<int>q;
    q.push(x);v[x] = 1;
    while(!q.empty()){
        int k = q.front();
        vis[k] = 0;
        q.pop();
        for(int i = 0; i < vec[k].size(); i++){
            int m = vec[k][i];
            if(!v[m] && d[m] > d[k]){
                v[m] = 1;
                q.push(m);
            }
        }
    }

}
void bfs_1(int x){
    int v[N] = {0};
    queue<int>q;
    for(int i = 1; i <= n; i++) v[i] = 0;
    q.push(x);v[x] = 1;
    while(!q.empty()){
        int k = q.front();
        vis[k] = 1;
        q.pop();
        for(int i = 0; i < vec[k].size(); i++){
            int m = vec[k][i];
            if(!v[m] && d[m] > d[k]){
                v[m] = 1;
                q.push(m);
            }
        }
    }
}
void dfs(int x){
    int flag = 0;
    if(x > dep){
        int ans = 0;
        for(int i = 1; i <= n; i++)
            if(vis[i]) ++ans;
        Min = min(Min,ans);
        return ;
    }
    for(int i = 0; i < tree[x].size(); i++){
        int k = tree[x][i];
        if(vis[k]){
            flag = 1;
            bfs_0(k);
            dfs(x + 1);
            bfs_1(k);
        }
    }
    if(!flag){
        int ans = 0;
        for(int i = 1; i <= n; i++)
            if(vis[i]) ++ans;
        Min = min(Min,ans);
        return ;
    }
}
int main(){
    cin >> n >> p;
    for(int i = 0; i < p; i++){
        int x,y;
        cin >> x >> y;
        vec[x].push_back(y);
        vec[y].push_back(x);
    }
    vis_bfs();
    for(int i = 1; i <= n; i++) vis[i] = 1;
    Min = 1e9;
    dfs(1);
    printf("%d\n",Min);
}

你可能感兴趣的:(深度优先搜索)