【P1330】封鎖陽光大學(圖論、BFS)
阿新 • • 發佈:2018-11-22
/* P1330 封鎖陽光大學 圖論 2018/11/22 */ #include<bits/stdc++.h> using namespace std; const int maxn=10010; vector<int>point[maxn];//STL鄰接表 queue<int>q;//bfs用 bool vis[maxn],color[maxn]; int ansb,answ,ans,n,m; void init(int u){ /* 子連通圖搜尋第一個點時的初始化 入隊+標記+染色+初始b,w的當前數 */ q.push(u); vis[u]=true; color[u]=true; ansb=1;//notice! answ=0; } bool bfs(){ while(!q.empty()){ int tmp=q.front();q.pop(); for(unsigned long int i=0;i<point[tmp].size();i++){ int u=point[tmp][i]; if(vis[u]){ if(color[tmp]==color[u]) returnfalse;//檢查 else continue; } q.push(u);//入隊 vis[u]=true; color[u]=!color[tmp];//染色(反色) if(color[u]) ansb++; else answ++; } //flag=!flag; } return true; } int main(){ memset(vis,false,sizeof(vis)); memset(color,0,sizeof(color)); cin>>n>>m; while(m--){ int a,b; cin>>a>>b; point[a].push_back(b); point[b].push_back(a); } ans=0; for(int i=1;i<=n;i++){ if(vis[i]) continue; init(i); if(!bfs()){cout<<"Impossible";return 0;} ans+=min(ansb,answ); } cout<<ans; return 0; }
利用BFS,來解決連通圖
意思就是,搜尋所有的結點,然後對其BFS並染色
染色時利用blank&white進行檢查
摘自洛谷題解
核心思想就是黑白間隔染色。
我們來分析一下題目。首先,肯定要明確一點,那就是這個圖是不一定聯通的。於是,我們就可以將整張圖切分成許多分開的連同子圖來處理。然而最重要的事情是:如何處理一個連通圖?
乍看下去,似乎無從下手,因為方案好像有很多種,根本就列舉不完。但是,關鍵要注意到題目中重要的兩個條件,我們把它抽象成這兩個要素:
①每一條邊所連線的點中,至少要有一個被選中。②每一條邊所連線的兩個點,不能被同時選中。由此,可以推斷出:
每一條邊都有且僅有一個被它所連線的點被選中。
又因為我們要處理的是一個連通圖。所以,對於這一個圖的點的選法,可以考慮到相鄰的點染成不同的顏色。
於是,對於一個連通圖,要不就只有兩種選法(因為可以全部選染成一種色的,也可以全部選染成另一種色的),要不就是impossible!
所以,我們只需要找到每一個子連通圖,對它進行黑白染色,然後取兩種染色中的最小值,然後最後彙總,就可以了。
另外,要判斷impossible,只需要加一個used陣列,記錄已經遍歷了哪些點。如果重複遍歷一個點,且與上一次的顏色不同,則必然是impossible的。