洛谷 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