結果
| 問題 |
No.3275 Minesweeper on Graph
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2024-07-31 14:06:11 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 33 ms / 2,000 ms |
| コード長 | 15,277 bytes |
| コンパイル時間 | 4,679 ms |
| コンパイル使用メモリ | 308,472 KB |
| 実行使用メモリ | 6,948 KB |
| 最終ジャッジ日時 | 2024-07-31 14:06:20 |
| 合計ジャッジ時間 | 8,290 ms |
|
ジャッジサーバーID (参考情報) |
judge3 / judge4 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 40 |
ソースコード
#include <bits/stdc++.h>
#define ll long long
#define ld long double
#define um unordered_map
#define us unordered_set
using namespace std;
const ll md1 = 998244353;
const ll md2 = 1e9 + 7;
const ll infll = LLONG_MAX;
typedef tuple<ll, vector<string>> query;
typedef vector<vector<ll>> twodint;
//==========
//入力ツール
//n個の入力を1つの整数リストとして受け取る
vector<ll> intlist(ll n){
vector<ll> v;
for(ll i = 0; i < n; i++){
ll a;
scanf("%lld", &a);
v.push_back(a);
}
return v;
}
//n行の入力を文字列のリストとして受け取る
vector<string> strtable(ll n){
vector<string> v;
for(ll i = 0; i < n; i++){
string s;
cin >> s;
v.push_back(s);
}
return v;
}
//1行m個の整数の入力をn行受け取ってリストにする
twodint intlisttable(ll n, ll m){
twodint v;
for(ll i = 0; i < n; i++){
v.push_back(intlist(m));
}
return v;
}
//n個のクエリを先頭だけ整数、他を文字列のリストとして受け取る
vector<query> getquery(ll n){ //cin入力後に使う場合は、直前にgetline(cin)で改行を取り除く
vector<query> v;
v.clear();
string s;
getline(cin, s);
for(ll i = 0; i < n; i++){
stringstream ss(s);
ll qr;
vector<string> vs;
ss >> qr;
string inpt;
while(ss >> inpt){
vs.push_back(inpt);
}
v.push_back({qr, vs});
getline(cin, s);
}
return v;
}
//==========
//出力ツール
//リストの中身を空白区切りで出力
template <typename T>
void printwithspace(vector<T> v){
for(auto it = v.begin(); it != v.end(); it++){
if(it != v.begin()){
cout << " ";
}
cout << *it;
}
cout << endl;
return;
}
//2次元リストの中身を1行ごと、空白区切りで出力
template <typename T>
void twodprintwithspace(vector<vector<T>> v){
for(auto it = v.begin(); it != v.end(); it++){
for(auto it2 = (*it).begin(); it2 != (*it).end(); it2++){
if(it2 != (*it).begin()){
cout << " ";
}
cout << *it2;
}
cout << endl;
}
return;
}
//==========
//unordered_map用の各種操作
//keyのリストを生成
template <typename T1, typename T2>
vector<T1> keys(um<T1, T2> d){
vector<T1> v;
for(auto it = d.begin(); it != d.end(); it++){
v.push_back((*it).first);
}
sort(v.begin(), v.end());
return v;
}
//valueのリストを作成
template <typename T1, typename T2>
vector<T2> values(um<T1, T2> d){
vector<T2> v;
for(auto it = d.begin(); it != d.end(); it++){
v.push_back((*it).second);
}
return v;
}
//==========
//数え上げ
//1次元数え上げ
template <typename T1, typename T2>
ll cntx(T1 itr, T2 x){
return count(itr.begin(), itr.end(), x);
}
//2次元数え上げ
template <typename T1, typename T2>
ll twodimcntx(T1 itr, T2 x){
ll sm = 0;
for(auto it = itr.begin(); it != itr.end(); it++){
sm += cntx(itr, x);
}
return sm;
}
//1次元全要素数え上げ
template <typename T1, typename T2>
unordered_map<T2, ll> cntall(T1 itr){
unordered_map<T2, ll> d;
for(auto it = itr.begin(); it != itr.end(); it++){
d.try_emplace(*it, 0);
d[*it]++;
}
return d;
}
//2次元全要素数え上げ
template <typename T1, typename T2>
unordered_map<T2, ll> twodimcntall(T1 itr){
unordered_map<T2, ll> d;
for(auto it = itr.begin(); it != itr.end(); it++){
for(auto it2 = (*it).begin(); it2 != (*it).end(); it2++){
d.try_emplace(*it2, 0);
d[*it2]++;
}
}
return d;
}
//==========
//計算ツール
//最大公約数
ll gcd(ll x, ll y){
if(x < y){
return gcd(y, x);
}
if(x % y == 0){
return y;
}
return gcd(y, x%y);
}
//最小公倍数
ll lcm(ll x, ll y){
ll g = gcd(x, y);
return (x * y) / g;
}
//フィボナッチ数列生成(0-indexで、a_0 = 0, a_1 = 1, 第n項まで生成)
vector<ll> genfib(ll n, ll m){ //m = 1ならmd1、m = 2ならmd2、それ以外ならmの値でmod
ll md = m;
if(m == 1){
md = md1;
}
else if(m == 2){
md = md2;
}
vector<ll> v = {0, 1};
for(ll i = 1; i < n; i++){
auto it1 = v.end() - 1;
auto it2 = v.end() - 2;
v.push_back(*it1 + *it2);
}
return v;
}
//各桁の総和
ll digitsum(ll x){
string s = to_string(x);
ll sm = 0;
for(auto it = s.begin(); it != s.end(); it++){
sm += *it - '0';
}
return sm;
}
//popcount
ll popcntll(ll x){
return static_cast<ll>(__builtin_popcountll(x));
}
//xの累乗リスト(0乗からn乗まで)
vector<ll> powtable(ll x, ll n, ll m){ //m = 1ならmd1, m = 2ならmd2, それ以外ならmでmod
ll md = m;
if(m == 1){
md = md1;
}
else if(m == 2){
md = md2;
}
vector<ll> v = {1};
for(ll i = 0; i < n; i++){
ll lst = *v.rbegin();
v.push_back((x*lst) % md);
}
return v;
}
//==========
//素数関連
set<ll> primeset;
vector<ll> primelist;
//素数テーブル生成
void genprimeset(ll n){
ll start = 2;
if(primelist.size() != 0){
start = *(primelist.rbegin()) + 1;
}
set<ll> ps = primeset;
for(ll i = start; i <= n; i++){
ps.insert(i);
}
auto it = ps.begin();
ll m = *it;
while(m*m <= (*ps.rbegin())){
ll now = m * 2;
while(now <= (*ps.rbegin())){
if(ps.find(now) != ps.end()){
ps.erase(now);
}
now += m;
}
it++;
m = *it;
}
primeset = ps;
return;
}
//素数テーブルの初期化
void primeinit(ll x){
genprimeset(x);
primelist.clear();
for(auto it = primeset.begin(); it != primeset.end(); it++){
primelist.push_back(*it);
}
return;
}
//素数判定
bool isitprime(ll x){
if(x < 2){
return false;
}
ll sr = static_cast<ll>(sqrt(x));
if(primelist.size() == 0){
primeinit(sr+10);
}
else{
ll p = *(primelist.rbegin());
if(p*p < x){
primeinit(sr+10);
}
}
if(primeset.contains(x)){
return true;
}
for(auto it = primelist.begin(); it != primelist.end(); it++){
if(x % (*it) == 0){
return false;
}
}
return true;
}
//素因数分解
tuple<vector<ll>, um<ll, ll>> factorize(ll x){
ll sr = static_cast<ll>(sqrt(x));
if(primelist.size() == 0){
primeinit(sr+10);
}
else{
ll p = *(primelist.rbegin());
if(p*p < x){
primeinit(sr+10);
}
}
um<ll, ll> dct;
ll now = x;
for(auto it = primelist.begin(); it != primelist.end(); it++){
ll p = *it;
if(x < p*p){
break;
}
while(now % p == 0){
if(!dct.contains(p)){
dct.insert({p, 0});
}
dct[p] += 1;
now /= p;
}
}
if(now != 1){
dct.insert({now, 1});
}
vector<ll> dctkey = keys(dct);
return {dctkey, dct};
}
//約数数え上げ
ll countdivisor(ll x){
vector<ll> k;
um<ll, ll> f;
tuple<vector<ll>, um<ll, ll>> t = factorize(x);
k = get<0>(t);
f = get<1>(t);
ll cnt = 1;
for(auto it = k.begin(); it != k.end(); it++){
cnt *= f[*it] + 1;
}
return cnt;
}
//約数列挙
vector<ll> divisor(ll x){
us<ll> s;
for(ll i = 1; i <= x; i++){
if(x < i*i){
break;
}
if(x % i == 0){
s.insert(i);
s.insert(x / i);
}
}
vector<ll> v;
for(auto it = s.begin(); it != s.end(); it++){
v.push_back(*it);
}
sort(v.begin(), v.end());
return v;
}
//==========
//英字変換
//大文字->小文字変換
char uppertolower(char c){
return static_cast<char>(toupper(c));
}
//小文字→大文字変換
char lowertoupper(char c){
return static_cast<char>(tolower(c));
}
//大文字小文字相互変換
char upperlower(char c){
char newc = uppertolower(c);
if(c == newc){
newc = lowertoupper(c);
}
return newc;
}
//文字列の大文字->小文字変換
string uppertolowerstr(string s){
string a = "";
for(ll i = 0; i < s.size(); i++){
char& c = s[i];
a.push_back(uppertolower(c));
}
return a;
}
//文字列の小文字->大文字変換
string lowertoupperstr(string s){
string a = "";
for(ll i = 0; i < s.size(); i++){
char& c = s[i];
a.push_back(lowertoupper(c));
}
return a;
}
//文字列の大小相互変換
string upperlowerstr(string s){
string a = "";
for(ll i = 0; i < s.size(); i++){
char& c = s[i];
a.push_back(upperlower(c));
}
return a;
}
//二分探索
//渡すvectorはソート済みにすること
//x以下の要素の個数
template <typename T>
ll xorless(vector<T> v, T x){
int ans = distance(v.begin(), upper_bound(v.begin(), v.end(), x));
return static_cast<ll>(ans);
}
//xより小さい要素の個数
template <typename T>
ll lessthanx(vector<T> v, T x){
int ans = distance(v.begin(), lower_bound(v.begin(), v.end(), x));
return static_cast<ll>(ans);
}
//x以上の要素の個数
template <typename T>
ll xormore(vector<T> v, T x){
int ans = v.size() - distance(v.begin(), lower_bound(v.begin(), v.end(), x));
return static_cast<ll>(ans);
}
//xより大きい要素の個数
template <typename T>
ll morethanx(vector<T> v, T x){
int ans = v.size() - distance(v.begin(), upper_bound(v.begin(), v.end(), x));
return static_cast<ll>(ans);
}
//==========
//繰り返し2乗法
um<ll, ll> powdct;
//powdctの初期化
void initpow(){
powdct.clear();
powdct.insert({0, 1});
return;
}
ll repeatpow(ll x, ll y, ll m){//m = 1ならmd1, m = 2ならmd2, それ以外ならmでmod
ll md = m;
if(m == 1){
md = md1;
}
else if(m == 2){
md = md2;
}
if(powdct.contains(y)){
return powdct[y];
}
ll a = 1;
if(y % 2 == 1){
a = x;
}
ll r = repeatpow(x, y/2, m);
a = (((r*r) % md)*a) % md;
powdct.insert({y, a});
return a;
}
ll powit(ll x, ll y, ll m){
initpow();
if(x == 0){
return 0;
}
return repeatpow(x, y, m);
}
//==========
//グラフツール(WIP)
//グラフ初期化
template <typename T>
vector<vector<ll>> defgraph(vector<T> vlist){
vector<vector<ll>> graph;
for(ll i = 0; i < vlist.size(); i++){
vector<ll> vct;
graph.push_back(vct);
}
return graph;
}
//elist生成(vlistはソート済みにすること)
template <typename T>
vector<tuple<ll, ll>> genelist(vector<T> vlist, vector<tuple<T, T>> rawe){
vector<tuple<ll, ll>> elist;
for(ll i = 0; i < rawe.size(); i++){
T& u = get<0>(rawe[i]);
T& v = get<1>(rawe[i]);
auto uit = lower_bound(vlist.begin(), vlist.end(), u);
auto vit = lower_bound(vlist.begin(), vlist.end(), v);
ll uidx = static_cast<ll>(distance(vlist.begin(), uit));
ll vidx = static_cast<ll>(distance(vlist.begin(), vit));
elist.push_back({uidx, vidx});
}
return elist;
}
//無向グラフ生成
template <typename T>
vector<vector<ll>> undirgraph(vector<T> vlist, vector<tuple<T, T>> rawe){
vector<vector<ll>> graph = defgraph<T>(vlist);
vector<tuple<ll, ll>> elist = genelist<T>(vlist, rawe);
for(ll i = 0; i < elist.size(); i++){
ll& u = get<0>(elist[i]);
ll& v = get<1>(elist[i]);
graph[u].push_back(v);
graph[v].push_back(u);
}
return graph;
}
//有向グラフ生成
template <typename T>
vector<vector<ll>> dirgraph(vector<T> vlist, vector<tuple<T, T>> rawe){
vector<vector<ll>> graph = defgraph<T>(vlist);
vector<tuple<ll, ll>> elist = genelist<T>(vlist, rawe);
for(ll i = 0; i < elist.size(); i++){
ll& u = get<0>(elist[i]);
ll& v = get<1>(elist[i]);
graph[u].push_back(v);
}
return graph;
}
//重み無し最短経路
template <typename T>
ll shortest(vector<T> vlist,\
vector<vector<ll>> graph,\
T st,\
T gl){
bool rule1 = find(vlist.begin(), vlist.end(), st) == vlist.end();
bool rule2 = find(vlist.begin(), vlist.end(), gl) == vlist.end();
if(rule1 || rule2){
return -1;
}
auto stitr = lower_bound(vlist.begin(), vlist.end(), st);
auto glitr = lower_bound(vlist.begin(), vlist.end(), gl);
ll stidx = static_cast<ll>(distance(vlist.begin(), stitr));
ll glidx = static_cast<ll>(distance(vlist.begin(), glitr));
us<ll> yet;
for(ll i = 0; i < vlist.size(); i++){
yet.insert(i);
}
yet.erase(stidx);
deque<tuple<ll, ll>> q;
q.push_back({stidx, 0});
while(q.size() != 0){
tuple<ll, ll>& now = q.front();
ll& v = get<0>(now);
ll& s = get<1>(now);
q.pop_front();
if(v == glidx){
return s;
}
for(ll i = 0; i < graph[v].size(); i++){
ll nxtv = graph[v][i];
if(yet.contains(nxtv)){
yet.erase(nxtv);
q.push_back({nxtv, s+1});
}
}
}
return -1;
}
//wdictの生成
template <typename T1, typename T2>
um<ll, T2> genwdict(vector<T1> vlist,\
vector<tuple<T1, T1, T2>> raww){
um<ll, T2> wdict;
for(ll i = 0; i < raww.size(); i++){
T1& u = get<0>(raww[i]);
T1& v = get<1>(raww[i]);
T2& w = get<2>(raww[i]);
auto uit = lower_bound(vlist.begin(), vlist.end(), u);
auto vit = lower_bound(vlist.begin(), vlist.end(), v);
ll uidx = static_cast<ll>(distance(vlist.begin(), uit));
ll vidx = static_cast<ll>(distance(vlist.begin(), vit));
ll widx = uidx * vlist.size() + vidx;
wdict.insert({widx, w});
}
return wdict;
}
//重み付きグラフ初期化
template <typename T1, typename T2>
vector<um<ll, T2>> defgraphw(vector<T1> vlist){
vector<um<ll, T2>> graph;
for(ll i = 0; i < vlist.size(); i++){
um<ll, T2> dct;
graph.push_back(dct);
}
return graph;
}
//重み付き無向グラフ生成
template <typename T1, typename T2>
vector<um<ll, T2>> undirgraphw(vector<T1> vlist,\
vector<tuple<T1, T1>> rawe,\
vector<tuple<T1, T1, T2>> raww){
vector<um<ll, T2>> graph = defgraphw<T1, T2>(vlist);
vector<tuple<ll, ll>> elist = genelist<T1>(vlist, rawe);
um<ll, T2> wdict = genwdict<T1, T2>(vlist, raww);
for(ll i = 0; i < elist.size(); i++){
ll& u = get<0>(elist[i]);
ll& v = get<1>(elist[i]);
ll wref = u * vlist.size() + v;
T2 w = wdict[wref];
graph[u].insert({v, w});
graph[v].insert({u, w});
}
return graph;
}
/* //ダイクストラ(WIP)
template <typename T1, typename T2>
um<ll, T2> dijkstra(vector<T1> vlist,\
vector<tuple<ll, ll>> elist,\
vector<um<ll, T2>> graph,\
T1 st){
um<ll, T2> cur;
for(ll i = 0; i < vlist.size(); i++){
cur.insert({i, static_cast<T2>(infll)});
}
} */
//==========
//問題要約
// N 頂点 M 辺の単純無向グラフが与えられる
// 頂点には 1 から N までの番号が、辺には 1 から M までの番号が振られている
// 辺 i(where 1<=i<=M)は頂点 U_i と頂点 V_i を結んでいる
// 各頂点には地雷が 0 個または 1 個埋まっている
// 頂点 k(where 1<=k<=N)に隣接する頂点に埋まっている地雷の個数の総和は A_k 個である
// これに矛盾しない地雷の埋め方が存在するかを判定し、存在するなら埋め方を 1 つ例示せよ
//
// 1 <= N <= 16
// 1 <= M <= N(N-1) // 2
// 0 <= A_i <= N-1
// 1 <= U_i, V_i <= N
// 入力はすべて整数
// グラフは単純無向グラフ
//
//==========
//コードはここから書く
int main(){
ll N, M;
cin >> N >> M;
vector<ll> vlist;
for(ll i = 1; i <= N; i++){
vlist.push_back(i);
}
vector<ll> A = intlist(N);
vector<tuple<ll, ll>> rawe;
for(ll i = 0; i < M; i++){
ll U, V;
cin >> U >> V;
rawe.push_back({U, V});
}
vector<vector<ll>> graph = undirgraph<ll>(vlist, rawe);
ll mx = powit(2, N, 1);
bool flag = true;
for(ll i = 0; i < mx; i++){
vector<ll> mineexists;
ll now = i;
for(ll j = 0; j < N; j++){
mineexists.push_back(now % 2);
now /= 2;
}
vector<ll> minecount;
for(ll j = 0; j < N; j++){
minecount.push_back(0);
}
for(ll j = 0; j < N; j++){
for(ll k = 0; k < graph[j].size(); k++){
minecount[j] += mineexists[graph[j][k]];
}
}
bool subflag = true;
for(ll j = 0; j < N; j++){
if(minecount[j] != A[j]){
subflag = false;
}
}
if(subflag){
flag = false;
cout << "Yes" << endl;
printwithspace<ll>(mineexists);
break;
}
}
if(flag){
cout << "No" << endl;
}
return 0;
}