洛谷 P1330 封锁阳光大学

洛谷 P1330 封锁阳光大学

Description

  • 曹是一只爱刷街的老曹,暑假期间,他每天都欢快地在阳光大学的校园里刷街。河蟹看到欢快的曹,感到不爽。河蟹决定封锁阳光大学,不让曹刷街。

    阳光大学的校园是一张由N个点构成的无向图,N个点之间由M条道路连接。每只河蟹可以对一个点进行封锁,当某个点被封锁后,与这个点相连的道路就被封锁了,曹就无法在与这些道路上刷街了。非常悲剧的一点是,河蟹是一种不和谐的生物,当两只河蟹封锁了相邻的两个点时,他们会发生冲突。

    询问:最少需要多少只河蟹,可以封锁所有道路并且不发生冲突。

Input

  • 第一行:两个整数N,M

    接下来M行:每行两个整数A,B,表示点A到点B之间有道路相连。

Output

  • 仅一行:如果河蟹无法封锁所有道路,则输出“Impossible”,否则输出一个整数,表示最少需要多少只河蟹。

Sample Input1

3 3
1 2
1 3
2 3

Sample Output1

Impossible

Sample Input2

3 2
1 2
2 3

Sample Output2

1

题解:

  • dfs。
  • 这题还不错欸QAQ。
  • 首先要知道,一个点的状态只有两种,不染色和染色。
  • 如果一个点染了色,它周围的点只能不染了;如果一个点没染,它周围的点必须要染,要不然就无法控制周围的点了。所以,换句话说,一但一个点的状态确定,周围点的状态也就确定。
  • 那么,第一想法就出来了:随便找个点x,以x染色为开始dfs 或者 以x不染色为开始dfs。在两种情况中找最小河蟹的。
  • 但是,这种想法可以再优化一下。假设现有一图已经按题意染好色了,河蟹数为sum1。这是以x染色为开始dfs的情况的答案是吧。其实,以x不染色为开始dfs的情况的答案就是[总点数 - sum1],也就是不染色的点数。仔细想想,将这个图黑点变白,白点变黑,也是一种合法的情况。而且这种情况满足了x不染色为开始dfs的情况。
  • 所以总结一下,随便找个点x,以x染色为开始dfs。记录染了的点数sum1和没染的点数sum2。然后ans = min(sum1, sum2)。
  • 但是,有个坑点,这个图可能不联通。所以要进行多次dfs,累加多次答案。
#include <iostream>
#include <cstdio>
#define N 10005
#define M 200005
using namespace std;

struct E {int next, to;} e[M];
int n, m, num, flag, sum1, sum2, ans;
int h[N], col[N];
bool vis[N];

int read()
{
    int x = 0; char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
    return x;
}

void add(int u, int v)
{
    e[++num].next = h[u];
    e[num].to = v;
    h[u] = num;
}

void dfs(int x, int tag)
{
    if(flag) return;
    if(tag == 1) sum1++;
    else sum2++;
    vis[x] = 1, col[x] = tag;
    for(int i = h[x]; i; i = e[i].next)
    {
        if(!vis[e[i].to]) dfs(e[i].to, -tag);
        else if(col[e[i].to] == tag) {flag = 1; return;}
    }
}

int main()
{
    cin >> n >> m;
    for(int i = 1; i <= m; i++)
    {
        int u = read(), v = read();
        add(u, v), add(v, u);
    }
    for(int i = 1; i <= n; i++)
        if(!vis[i])
        {
            sum1 = sum2 = flag = 0;
            dfs(i, 1);
            if(flag) {cout << "Impossible"; return 0;}
            else ans += min(sum1, sum2);
        }
    cout << ans;
    return 0;
}

转载于:https://www.cnblogs.com/BigYellowDog/p/11438859.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值