14130: 【原4130】This is a NP-Hard Problem
题目
题目描述
author: Lmxyy 原OJ链接:https://acm.sjtu.edu.cn/OnlineJudge-old/problem/4130
Description
最近dhh带着xyy对NP-Hard问题进行了一些研究,他们发现最小点覆盖问题特别有趣。
所谓点覆盖,即给你一张图\(G(V,E)\)和他的一个点集\(A\)。如果对于\(G\)中的任何一条边\(u,v\),都要么有\(u \in A\)或者\(v \in A\),则\(A\)称为\(G\)的一个点覆盖。
由于dhh打乒乓球太腻害了,所以他赢得了一张\(N\)个点\(M\)条边的无向图,现在他准备把图中的点分成不相交的两份,拿出来一份送给xyy。xyy欣然接受,但他希望他所得到点是原图中的一个点覆盖;dhh同时也希望他留下的那份是原图中一个点覆盖。
现在他们想知道是否存在这样一种分法,能够同时满足两个人的要求。
Input Format
第一行一个正整数\(T\),表示数据组数。
对于每组数据,第一行两个正整数\(N\)和\(M\),意义如题意。
接下来\(M\)行,每行两个正整数\(u,v\),表示图中的一条边。
Output Format
每组数据各输出一行,\(1\)表示可以满足两人要求,\(-1\)表示无法满足要求。
Sample Input 1
1
4 2
1 2
2 3
Sample Output 1
1
Sample Input 2
1
3 3
1 2
2 3
1 3
Sample Output 2
-1
Data Range
对于\(30 \%\)的数据,\(N \le10 \),\(M \le 20\)。
对于\(60 \%\)的数据,\(N \le1000 \),\(M \le 2000\)。
对于\(100 \%\)的数据,\(2 \le N \le 100000\),\(0 \le M \le 200000\),\(T = 10\)。点的编号以\(1\)开始。
Hint
若果遇到莫名其妙tle,请关闭同步或改用scanf读入。
FineArtz's solution
/* This is a NP-Hard Problem */
#include <cstdio>
#include <cstring>
using namespace std;
int n, m;
int be[100005], head[100005], nxt[400005], edg[400005], cnt;
inline void addEdge(int u, int v){
++cnt;
nxt[cnt] = head[u];
edg[cnt] = v;
head[u] = cnt;
}
bool check(int st){
int q[100005] = {0};
int front = 0, rear = 0;
be[st] = 1;
q[rear++] = st;
while (front != rear){
int now = q[front++];
for (int i = head[now]; i; i = nxt[i]){
if (be[edg[i]] == 0){
int v = edg[i];
be[v] = (be[now] == 1 ? -1 : 1);
q[rear++] = v;
}
else if (be[edg[i]] != -be[now])
return false;
}
}
return true;
}
int main(){
int t;
scanf("%d", &t);
while (t--){
scanf("%d%d", &n, &m);
memset(be, 0, sizeof(be));
memset(head, 0, sizeof(head));
memset(nxt, 0, sizeof(nxt));
memset(edg, 0, sizeof(edg));
cnt = 0;
for (int i = 1; i <= m; ++i){
int u, v;
scanf("%d%d", &u, &v);
addEdge(u, v);
addEdge(v, u);
}
bool flag = true;
for (int i = 1; i <= n; ++i){
if (head[i] != 0 && be[i] == 0){
if (!check(i)){
flag = false;
printf("-1\n");
break;
}
}
}
if (flag)
printf("1\n");
}
return 0;
}
WashSwang's solution
#include <cstdio>
#include <cstring>
using namespace std;
int ne[400010],to[400010],last[400010],num,k[400010],tail,head,ans;
int t,m,n,u,v;
void add(int u,int v)
{
ne[++num]=last[u];
to[num]=v;
last[u]=num;
}
int dfs(int x)
{
for (int i=last[x];i!=0;i=ne[i])
{
if (!k[to[i]])
{
k[to[i]]=-k[x];
if (!dfs(to[i])) return 0;
}
else
if (k[to[i]]+k[x]!=0)
return 0;
}
return 1;
}
int main() {
scanf("%d",&t);
for (int i=0;i<t;++i) {
scanf("%d%d", &n, &m);
num=0;
memset(last, 0, sizeof(last));
memset(k, 0, sizeof(k));
for (int j = 0; j < m; ++j) {
scanf("%d%d", &u, &v);
add(u,v);
add(v,u);
}
ans=1;
for (int j=1;j<=n;++j)
if (k[j]==0){
k[j]=1;
if (!dfs(j))
{
ans=-1;
break;
}
}
printf("%d\n",ans);
}
return 0;
}