1. 程式人生 > >P1330 封鎖陽光大學(染色+dfs)

P1330 封鎖陽光大學(染色+dfs)

傳送門

題解:

第一種:染色+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;
}

第二種: