P1330 封鎖陽光大學(染色+dfs)
阿新 • • 發佈:2018-12-10
題解:
第一種:染色+dfs
①每一條邊所連線的點中,至少要有一個被選中。②每一條邊所連線的兩個點,不能被同時選中。由此,可以推斷出:
每一條邊都有且僅有一個被它所連線的點被選中。
又因為我們要處理的是一個連通圖。所以,對於這一個圖的點的選法,可以考慮到相鄰的點染成不同的顏色。於是,對於一個連通圖,要不就只有兩種選法(因為可以全部選染成一種色的,也可以全部選染成另一種色的),要不就是impossible!
只需要找到每一個子連通圖,對它進行黑白染色,然後取兩種染色中的最小值,然後最後彙總,就可以了。
另外,要判斷impossible,只需要加一個used陣列,記錄已經遍歷了哪些點。如果重複遍歷一個點,且與上一次的顏色不同,則必然是impossible的。
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+50; struct edge{ int v,next; }; edge edges[maxn]; int head[maxn],cnt=0; bool used[maxn]; int col[maxn]; int sum[2]; int n,m; void add(int a,int b) { edges[cnt].v=b; edges[cnt].next=head[a]; head[a]=cnt++; } bool dfs(int node,int color) { if(used[node]){ if(col[node]==color){ return true; } return false; } used[node]=true; sum[col[node]=color]++; bool tf=true; for(int i=head[node];~i;i=edges[i].next){ tf=tf&&dfs(edges[i].v,1-color); } return tf; } int main() { memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); int a,b; for(int i=1;i<=m;i++){ scanf("%d%d",&a,&b); add(a,b); add(b,a); } int ans=0; for(int i=1;i<=n;i++){ if(used[i]){ continue; } sum[0]=sum[1]=0; if(!dfs(i,0)){ printf("Impossible\n"); return 0; } ans+=min(sum[0],sum[1]); } printf("%d\n",ans); return 0; }
第二種: