洛谷 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;
}