其他分享
首页 > 其他分享> > 洛谷 P1330 封锁阳光大学

洛谷 P1330 封锁阳光大学

作者:互联网

分析题目,我们可以发现:由于要把每条边都封锁了,而一条边必有两个端点,说明这两个端点必定要有一个放上河蟹。据此,我们枚举一个点i,将他先放上河蟹,然后对于他的所有由边连出去的点,都不用放河蟹,而这些点再又通过连出去的边所连到的点,就必须放河蟹了,由此进行DFS,直到每个点都确定放或不放上河蟹为止。

另外,判断无解的情况则是,一个点,他之前已经被其他点搜索到了,并确定了放或不放上河蟹了,此时,他又被搜索到,而此时他已有的状态与现在要给他的状态不同,说明矛盾,输出Impossible,结束程序。

关于number,因为有可能,在一个无向图中,有多个小图,这些小图互相“独立”。那么在搜索时,我们就可以借助number来算这个小图的点的个数

关于min(temp,number-temp),temp等于假设点i放上河蟹后整个图放河蟹的个数,而number-temp则表示将所有没放上河蟹的点放上河蟹,原本有河蟹的都去掉,同样也可以封锁所有道路,比较这两个的大小,从而取得最优解。

关于vis数组,用来表示这个点有没有被访问过,如果被访问过,说明他所在的“小图”已经处理好了,没必要再处理了。

dfs函数中的if(c[now]==r),这个点被搜索到多次,而现在的状态与现在要给他的状态一样,那么他接下来要对他连出去的边所到达的点要做的操作就一样了,所以没必要再重复进行这次搜索,直接return;

最后,附上代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,vis[10010],c[10010],ans=0,number=0;
vector<int> g[10010];
void dfs(int now,int r){
    if(c[now]!=-1 && c[now]!=r){
        printf("Impossible\n");
        exit(0);
    }
    if(c[now]==r){
        return;
    }
    c[now]=r;
    vis[now]=1;
    number++;
    for(int i=0;i<g[now].size();i++){
        dfs(g[now][i],r^1);
    }
}
int main(){
    memset(vis,0,sizeof(vis));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        g[x].push_back(y);
        g[y].push_back(x);
    }
    for(int i=1;i<=n;i++){
        if(vis[i]==0){
            memset(c,-1,sizeof(c));
            number=0;
            dfs(i,0);
            int temp=0;
            for(int j=1;j<=n;j++){
                if(c[j]==1)temp+=c[j];
            }
            ans+=min(temp,number-temp);
        }
    }
    printf("%d",ans);
    return 0;
} 

 

标签:封锁,河蟹,洛谷,temp,int,number,小图,now,P1330
来源: https://www.cnblogs.com/Laehcim/p/10803288.html