题意:n个点m条边的无向图,要求给n个点赋值,每个点可以赋为1、2、3中的一个,n个点共有n1个值为1的点,n2个值为2的点,n3个值为3的点,要求每条边两端点的差刚好为1
二分图染色,1,3实质是相同的,将图分为多个二分连通块,然后找一下能否刚好n2个点
#include<bits/stdc++.h>
using namespace std;
vector<int>g[5005],sum[5005][2];
int n, m;
int a, b, c,k;
int col[5005];
int ok = 1;
int cnt;
int dp[5005][5005];
char ans[5005];
void dfs(int u, int f, int color)
{col[u] = color;sum[cnt][color].push_back(u);for (auto v : g[u]){if (v == f)continue;if (col[v] == -1){dfs(v, u, !color);}else if (col[v] == col[u])ok = 0;}
}
int main()
{cin >> n >> m;cin >> a >> b >> c;while (m--){int x, y;cin >> x >> y;g[x].push_back(y);g[y].push_back(x);} memset(col, -1, sizeof(col));for (int i = 1; i <= n; i++){if (col[i] == -1){dfs(i, 0, 1);cnt++;}}if (!ok){printf("NO\n");}else{dp[0][0] = 1;for (int i = 0; i < cnt; i++){int x = sum[i][0].size(), y = sum[i][1].size();for (int j = 0; j <= b; j++){if (dp[i][j]){if (j + y <= b)dp[i + 1][j + y] = 1;if (j + x <= b)dp[i + 1][j + x] = 1;}}}//cout << cnt <<" "<< b << endl;if (!dp[cnt][b]){printf("NO\n");}else{k = b;for (int i = cnt; i > 0; i--){int v;if (dp[i - 1][k - sum[i - 1][0].size()])v = 0;else v = 1;k -= sum[i - 1][v].size();for (auto xx : sum[i - 1][v]){ans[xx] = '2';}}for (int i = 1; i <= n; i++){if (ans[i] != '2') {if (a)ans[i] = '1', a--;else ans[i] = '3';}}printf("YES\n%s\n", ans + 1);}}
}