傳送門:https://codeforces.com/problemset/problem/242/D
對於一個點,顯然一旦達到額定值後,其他任何操作都無法使他減小,於是我們得出一個貪心性質,當且僅當一個點不合法時,才取增加他的值。同理,我們可以證明,問題必定有解,因為若一個點被選擇,必定是因為其曾不合法,選擇後使其\(+1\)合法,而若最後一個點不合法,其必定是未選擇的,選擇其則能合法。過程可以用佇列維護。時間複雜度\(O(n)\)。
#include <bits/stdc++.h>
using namespace std;
inline int read() {
char c;
bool flag = false;
while ((c = getchar()) < '0' || c > '9') if (c == '-') flag = true;
int res = c - '0';
while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + c - '0';
return flag ? -res : res;
}
const int N = 1e5 + 10;
int head[N], cnt, a[N], b[N], step[N];
struct Edge {
int v, next;
} e[N * 2];
void add(int u, int v) {
e[cnt].v = v;
e[cnt].next = head[u];
head[u] = cnt++;
}
int main() {
memset(head, -1, sizeof head);
int n = read(), m = read();
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) a[i] = read();
int ans = 0;
queue<int> q;
for (int i = 1; i <= n; ++i) if (!a[i]) q.push(i);
while (!q.empty()) {
if (b[q.front()] != a[q.front()]) {
q.pop();
continue;
}
step[++ans] = q.front();
++b[q.front()];
q.pop();
for (int i = head[step[ans]]; ~i; i = e[i].next) {
if (++b[e[i].v] == a[e[i].v]) q.push(e[i].v);
}
}
printf("%d\n", ans);
for (int i = 1; i <= ans; ++i) {
printf("%d ", step[i]);
}
return 0;
}