P1330 封锁阳光大学
原题链接 https://www.luogu.com.cn/problem/P1330
思路
这题思路应该挺多,我经过思索后,感觉可以染色。
如果一条边的一端有河蟹,那么另一端必然没有;而如果一端没有河蟹,那么另一端一定有。所以,遍历每条边(至少一端已经染色),如果另一端没有染色,则染上和这一端相反的颜色;如果都已经染色,判断是否相反,是就不管,不是就一定 $Impossible$ 。
由于要按边遍历,数据范围又超大,只能用邻接表,具体见代码。
再说广搜。需要每染色一个点就把此点放进队列,并标记。我选择广搜的原因是不用递归,发现不满足就可以直接返回。
细节
这道题其实细节挺多。
首先,为了方便遍历,建边时要建双向边。
其次,原图并非连通图,所以应该每个点都搜一次(搜过就不搜了),即在主函数上加一层循环。
如果可以满足,就要统计河蟹最小个数,也就是在每次广搜都统计一遍,再加起来。其实每次的个数就是两种颜色用的少的的个数,注意在每次搜完后都要求值。
$Code$:
#include<cstdio> #include<algorithm> #include<queue> using namespace std; const int MAXN=10010,MAXM=200010; int n,m,tot=0,sum[3],ans=0; int h[MAXN],vis[MAXN]; struct node { int v; int next; }e[MAXM]; void add(int u,int v) { tot++; e[tot].v=v; e[tot].next=h[u];h[u]=tot; } queue<int> q; bool bfs(int start) { vis[start]=1; sum[1]=1,sum[2]=0; q.push(start); while(!q.empty()) { int u=q.front();q.pop(); for(int k=h[u];k;k=e[k].next) { int v=e[k].v; if(vis[v]==vis[u]) return 1; if(vis[v]==0) { vis[v]=vis[u]%2+1; sum[vis[v]]++; q.push(v); } } } return 0; } int main() { scanf("%d%d",&n,&m); while(m--) { int u,v; scanf("%d%d",&u,&v); add(u,v); add(v,u); } for(int i=1;i<=n;i++) { if(vis[i]) continue; if(bfs(i)) { printf("Impossible"); return 0; } else ans+=min(sum[1],sum[2]); } printf("%d",ans); return 0; }