1. 程式人生 > >【P1330】封鎖陽光大學(圖論、BFS)

【P1330】封鎖陽光大學(圖論、BFS)

/*
    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]) return
false;//檢查 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的。