题意:
给定一个N≤500的无向图,现要根据图还原一个字符串s1s2...sn,字符集只有a,b,c
若(u,v)有边则abs(su−sv)≤1,无边则abs(su−sv)=2
求这个字符串,无解输出No
分析:
考虑无边的情况,显然(u,v)只能是(a,c)或者(c,a)
那么可以考虑把无边的单独拿出来建图,跑二分图染色,搞出一个可行解
假设a=−1,b=0,c=1,搞出可行解之后还要判断,原图与此是否矛盾
如果有边,col[u]∗col[v]<0,即是(a,c),则是矛盾的
如果无边,col[u]∗col[v]≥0,即是(b,b),(a,b),(b,c),则是矛盾的
如果没有矛盾,则此解可行,按照染色输出即可
时间复杂度O(n2+n+m)
代码:
//
// Created by TaoSama on 2016-02-05
// Copyright (c) 2016 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
using namespace std;
#define pr(x) cout << #x << " = " << x << " "
#define prln(x) cout << #x << " = " << x << endl
const int N = 5e2 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
int n, m;
int g[N][N], col[N];
char ans[N];
vector<int> G[N];
bool dfs(int u, int c) {
col[u] = c;
for(int v : G[u]) {
if(col[v] == col[u]) return false;
if(!col[v] && !dfs(v, -c)) return false;
}
return true;
}
int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
// freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);
while(scanf("%d%d", &n, &m) == 2) {
memset(g, 0, sizeof g);
for(int i = 1; i <= m; ++i) {
int u, v; scanf("%d%d", &u, &v);
g[u][v] = g[v][u] = 1;
}
for(int i = 1; i <= n; ++i) {
G[i].clear();
for(int j = 1; j <= n; ++j)
if(i != j && !g[i][j]) G[i].push_back(j);
}
bool yes = true;
memset(col, 0, sizeof col);
for(int i = 1; i <= n; ++i) {
if(!col[i] && G[i].size() && !dfs(i, 1)) {
yes = false;
break;
}
}
// for(int i = 1; i <= n; ++i) printf("col[%d]=%d\n", i, col[i]);
// printf("col : %d\n", yes);
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= n; ++j) {
if(i == j) continue;
if(g[i][j] && col[i] * col[j] < 0) yes = false;
if(!g[i][j] && col[i] * col[j] >= 0) yes = false;
}
}
if(!yes) {puts("No"); continue;}
puts("Yes");
for(int i = 1; i <= n; ++i) putchar("abc"[col[i] + 1]);
puts("");
}
return 0;
}
Comment里瞅见了一个贪心的解法,与二分图染色不同的是,这个先确定b
可以发现b应该是与所有边相连的,即deg[b]=n−1,确定了b之后
如果这个点没被确定,就丢a,如果有边跟它相连也丢a,否则丢c
丢完之后判断一下与题目的条件是否有矛盾
时间复杂度O(n2)
#include <bits/stdc++.h>
using namespace std;
int cnt[555];
bool edge[555][555];
char ans[555];
int main() {
int n, m;
cin >> n >> m;
for(int i = 0; i < m; ++i) {
int x, y;
cin >> x >> y;
--x, --y;
edge[x][y] = edge[y][x] = 1;
cnt[x]++;
cnt[y]++;
}
for(int i = 0; i < n; ++i) {
if(cnt[i] == n - 1)
ans[i] = 'b';
}
for(int i = 0; i < n; ++i) {
if(!ans[i]) {
ans[i] = 'a';
for(int j = 0; j < n; ++j) {
if(!ans[j]) {
if(edge[i][j])
ans[j] = 'a';
else
ans[j] = 'c';
}
}
}
}
for(int i = 0; i < n; ++i) {
for(int j = 0; j < n; ++j) {
if(i == j)
continue;
if((abs(ans[i] - ans[j]) == 2 && edge[i][j]) || (abs(ans[i] - ans[j]) < 2
&& !edge[i][j])) {
cout << "No";
return 0;
}
}
}
cout << "Yes\n" << ans << endl;
return 0;
}