Submission #1864904
Source Code Expand
#pragma GCC optimize ("O3")
#pragma GCC target ("avx")
#include "bits/stdc++.h" // define macro "/D__MAI"
using namespace std;
typedef long long int ll;
#define xprintf(fmt,...) fprintf(stderr,fmt,__VA_ARGS__)
#define debugv(v) {printf("L%d %s > ",__LINE__,#v);for(auto e:v){cout<<e<<" ";}cout<<endl;}
#define debuga(m,w) {printf("L%d %s > ",__LINE__,#m);for(int x=0;x<(w);x++){cout<<(m)[x]<<" ";}cout<<endl;}
#define debugaa(m,h,w) {printf("L%d %s >\n",__LINE__,#m);for(int y=0;y<(h);y++){for(int x=0;x<(w);x++){cout<<(m)[y][x]<<" ";}cout<<endl;}}
#define ALL(v) (v).begin(),(v).end()
#define repeat(cnt,l) for(auto cnt=0ll;(cnt)<(l);++(cnt))
#define iterate(cnt,b,e) for(auto cnt=(b);(cnt)!=(e);++(cnt))
#define MD 1000000007ll
#define PI 3.1415926535897932384626433832795
#define EPS 1e-12
template<typename T1, typename T2> ostream& operator <<(ostream &o, const pair<T1, T2> p) { o << "(" << p.first << ":" << p.second << ")"; return o; }
template<typename iterator> inline size_t argmin(iterator begin, iterator end) { return distance(begin, min_element(begin, end)); }
template<typename iterator> inline size_t argmax(iterator begin, iterator end) { return distance(begin, max_element(begin, end)); }
template<typename T> T& maxset(T& to, const T& val) { return to = max(to, val); }
template<typename T> T& minset(T& to, const T& val) { return to = min(to, val); }
void bye(string s, int code = 0) { cout << s << endl; exit(0); }
mt19937_64 randdev(8901016);
inline ll rand_range(ll l, ll h) {
return uniform_int_distribution<ll>(l, h)(randdev);
}
#if defined(_WIN32) || defined(_WIN64)
#define getchar_unlocked _getchar_nolock
#define putchar_unlocked _putchar_nolock
#elif __GNUC__
#else
#define getchar_unlocked getchar
#define putchar_unlocked putchar
#endif
namespace {
#define isvisiblechar(c) (0x21<=(c)&&(c)<=0x7E)
class MaiScanner {
public:
template<typename T> void input_integer(T& var) {
var = 0; T sign = 1;
int cc = getchar_unlocked();
for (; cc<'0' || '9'<cc; cc = getchar_unlocked())
if (cc == '-') sign = -1;
for (; '0' <= cc&&cc <= '9'; cc = getchar_unlocked())
var = (var << 3) + (var << 1) + cc - '0';
var = var*sign;
}
inline int c() { return getchar_unlocked(); }
inline MaiScanner& operator>>(int& var) { input_integer<int>(var); return *this; }
inline MaiScanner& operator>>(long long& var) { input_integer<long long>(var); return *this; }
inline MaiScanner& operator>>(string& var) {
int cc = getchar_unlocked();
for (; !isvisiblechar(cc); cc = getchar_unlocked());
for (; isvisiblechar(cc); cc = getchar_unlocked())
var.push_back(cc);
}
template<typename IT> void in(IT begin, IT end) { for (auto it = begin; it != end; ++it) *this >> *it; }
};
class MaiPrinter {
public:
template<typename T>
void output_integer(T var) {
if (var == 0) { putchar_unlocked('0'); return; }
if (var < 0)
putchar_unlocked('-'),
var = -var;
char stack[32]; int stack_p = 0;
while (var)
stack[stack_p++] = '0' + (var % 10),
var /= 10;
while (stack_p)
putchar_unlocked(stack[--stack_p]);
}
inline MaiPrinter& operator<<(char c) { putchar_unlocked(c); return *this; }
inline MaiPrinter& operator<<(int var) { output_integer<int>(var); return *this; }
inline MaiPrinter& operator<<(long long var) { output_integer<long long>(var); return *this; }
inline MaiPrinter& operator<<(char* str_p) { while (*str_p) putchar_unlocked(*(str_p++)); return *this; }
inline MaiPrinter& operator<<(const string& str) {
const char* p = str.c_str();
const char* l = p + str.size();
while (p < l) putchar_unlocked(*p++);
return *this;
}
template<typename IT> void join(IT begin, IT end, char sep = '\n') { for (auto it = begin; it != end; ++it) *this << *it << sep; }
};
}
MaiScanner scanner;
MaiPrinter printer;
class Graph {
public:
size_t n;
vector<vector<int>> vertex_to;
Graph(size_t n = 1) :n(n), vertex_to(n) {}
void connect(int from, int to) {
vertex_to[(size_t)from].emplace_back(to);
vertex_to[(size_t)to].emplace_back(from);
}
void resize(size_t _n) {
n = _n;
vertex_to.resize(_n);
}
};
inline int bitcount(int x) {
return bitset<31>(x).count();
}
int vertex_cover_AC(const Graph& graph) {
const int n = graph.n;
const int n_A = n / 2;
const int n_B = n - n_A;
const int inf = 1e9;
// 少なすぎるケースは回避
if (n < 6) abort();
// group A : i < n_A
// group B : i >= n_A
// dp[S] : S \subseteq V_A,
vector<int> ans_partial_A(1 << n_A, 0);
// Sが独立集合なら0,独立集合でないならinfとなるように初期状態を構成する.
for (int i = 0; i < n_A; ++i) {
int bit = 1 << i;
for (int j : graph.vertex_to[i])
if (j < n_A)
ans_partial_A[bit | (1 << j)] = inf; // 頂点数2
}
for (int bit = 3; bit < 1 << n_A; ++bit) {
if (bitcount(bit) <= 1) continue;
for (int i = 0; i < n_A; ++i) {
ans_partial_A[bit | (1 << i)] |= ans_partial_A[bit];
}
}
// groupA の部分集合の解を全列挙
// ここでは groupA と groupB のカットエッジの被覆は考えない.
for (int bit = 1; bit < 1 << n_A; ++bit) {
for (int i = 0; i < n_A; ++i) {
if (bit & (1 << i)) continue;
ans_partial_A[bit | (1 << i)] = min(
ans_partial_A[bit | (1 << i)],
ans_partial_A[bit] + 1
);
}
}
// dp[S] Sは独立集合ではない
vector<int> not_independent_B(1 << n_B, 0);
for (int _i = 0; _i < n_B; ++_i) {
int bit = 1 << _i;
for (int j : graph.vertex_to[n_A + _i])
if (n_A <= j)
not_independent_B[bit | (1 << (j - n_A))] = 1;
}
for (int bit = 3; bit < 1 << n_B; ++bit) {
if (bitcount(bit) <= 1) continue;
for (int _i = 0; _i < n_B; ++_i) {
not_independent_B[bit | (1 << _i)] |= not_independent_B[bit];
}
}
// dp[S] Sに隣接する頂点のbit配列
vector<int> adjacent2B(1 << n_B, 0);
for (int _i = 0; _i < n_B; ++_i) {
int bit = 0;
for (int j : graph.vertex_to[n_A + _i])
if (j < n_A)
bit |= 1 << j;
adjacent2B[1 << _i] = bit;
}
for (int bit = 1; bit < 1 << n_B; ++bit) {
for (int _i = 0; _i < n_B; ++_i) {
adjacent2B[bit | (1 << _i)] |= adjacent2B[bit];
}
}
// answer
int best = inf;
// groupB の部分集合を全列挙
for (int bit = 0; bit < 1 << n_B; ++bit) {
// choice_Bが頂点被覆でないなら,reject
if (not_independent_B[((1 << n_B) - 1) ^ bit]) continue;
int mask_A = (1 << n_A) - 1;
int fix_A = 0;
int adj = adjacent2B[((1 << n_B) - 1) ^ bit];
for (int i = 0; i < n_A; ++i) {
// choice_B で選んでいない頂点が,groupAと隣接するならば
if (adj & (1 << i)) {
// そのgroupAの頂点は必ず選択する.
mask_A ^= 1 << i; // 頂点jは考慮しなくてよい
++fix_A; // 必ず選択することにしたので
}
}
best = min(best, ans_partial_A[mask_A] + bitcount(bit) + fix_A);
}
return best;
}
//
int vertex_cover(const Graph& graph) {
const int n = graph.n;
// cover[i] = -1 : 未決定
// 0 : 選択しない
// 1 : 選択する
function<bool(const Graph&, const vector<int>&)> iscover = [](const Graph& graph, const vector<int>& cover) {
for (int j = 0; j < graph.n; ++j)
if (cover[j] == 0)
for (int to : graph.vertex_to[j])
if (!cover[to])
return false;
return true;
};
int best = n;
function<void(int, vector<int>, int)> dfs = [&](int idx, vector<int> cover, int cnt) {
// 選択した頂点の数
//int cnt = 0;
//for (int e : cover) cnt += (e == 1);
// これ以上選択する頂点を増やすと暫定の最良を超える
if (best <= cnt) return;
if (idx == n) {
// すべての頂点を決めた
if (iscover(graph, cover)) {
// 頂点被覆なら更新
best = min(best, cnt);
}
}
else if (cover[idx] != -1) {
// 今見る頂点が既に定まっているのでスキップ
dfs(idx + 1, cover, cnt);
}
else {
bool unnecessary = true;
for (int ad : graph.vertex_to[idx])
if (cover[ad] == 0) {
// 選択しないと決めた頂点に隣接するならば,
// 「頂点idxを選択しない」は出来ない.頂点idxを選択する.
cover[idx] = 1;
dfs(idx + 1, cover, cnt + 1);
return;
}
else
unnecessary &= cover[ad] == 1;
if (unnecessary) {
// 隣接する辺がすべて被覆されているならば,選択する必要は無い.
cover[idx] = 0;
dfs(idx + 1, cover, cnt);
return;
}
// 頂点idxを選択して再帰を続ける.
cover[idx] = 1;
dfs(idx + 1, cover, cnt + 1);
// 頂点idxを選択せず再帰を続ける.
cover[idx] = 0;
for (int ad : graph.vertex_to[idx])
cnt += (cover[ad] != 1), // 選択しない頂点の隣接は
cover[ad] = 1; // 必ず選択される
dfs(idx + 1, cover, cnt);
}
};
vector<int> ini(n, -1);
for (int j = 0; j < graph.n; ++j) {
// 次数が0の頂点は選択しない
if (graph.vertex_to[j].empty())
ini[j] = 0;
}
dfs(0, ini, 0);
return best;
}
void judge_random_local() {
randdev = mt19937_64(random_device()());
repeat(lop, 1000) {
clog << lop << endl;
int n = rand_range(6, 8);
set<pair<int, int>> edges;
repeat(i, 20) {
int u = rand_range(0, n - 1);
int v = rand_range(0, n - 2);
if (u == v) ++v;
if (u > v) swap(u, v);
edges.emplace(u, v);
}
Graph graph(n);
for (auto e : edges)
graph.connect(e.first, e.second);
int ans1 = vertex_cover(graph);
int ans2 = vertex_cover_AC(graph);
if (ans1 != ans2) {
cout << "Wrong answer" << endl;
cout << "ans1 : " << ans1 << endl;
cout << "ans2 : " << ans2 << endl;
cout << n << " " << edges.size() << endl;
for (auto e : edges)
cout << e.first+1 << " " << e.second+1 << endl;
exit(0);
}
}
exit(0);
}
int main() {
//judge_random_local();
int m, n;
scanner >> n >> m;
if (m == 0) {
cout << n << endl;
return 0;
}
Graph graph(n);
repeat(i, m) {
int a, b;
scanner >> a >> b;
--a; --b;
graph.connect(a, b);
}
auto cover = vertex_cover(graph);
// 頂点被覆を反転させると独立集合なので,
int ans = n - cover;
printer << ans << '\n';
return 0;
}
Submission Info
Submission Time |
|
Task |
G - Mixture Drug |
User |
m_buyoh |
Language |
C++14 (GCC 5.4.1) |
Score |
600 |
Code Size |
12291 Byte |
Status |
AC |
Exec Time |
309 ms |
Memory |
256 KB |
Judge Result
Set Name |
Sample |
All |
Score / Max Score |
0 / 0 |
600 / 600 |
Status |
|
|
Set Name |
Test Cases |
Sample |
sample_01.txt, sample_02.txt, sample_03.txt |
All |
sample_01.txt, sample_02.txt, sample_03.txt, subtask_1_1.txt, subtask_1_10.txt, subtask_1_11.txt, subtask_1_12.txt, subtask_1_13.txt, subtask_1_14.txt, subtask_1_15.txt, subtask_1_16.txt, subtask_1_17.txt, subtask_1_18.txt, subtask_1_19.txt, subtask_1_2.txt, subtask_1_20.txt, subtask_1_21.txt, subtask_1_22.txt, subtask_1_23.txt, subtask_1_24.txt, subtask_1_25.txt, subtask_1_26.txt, subtask_1_27.txt, subtask_1_28.txt, subtask_1_29.txt, subtask_1_3.txt, subtask_1_30.txt, subtask_1_31.txt, subtask_1_32.txt, subtask_1_33.txt, subtask_1_34.txt, subtask_1_35.txt, subtask_1_36.txt, subtask_1_37.txt, subtask_1_38.txt, subtask_1_39.txt, subtask_1_4.txt, subtask_1_40.txt, subtask_1_41.txt, subtask_1_42.txt, subtask_1_43.txt, subtask_1_44.txt, subtask_1_45.txt, subtask_1_46.txt, subtask_1_47.txt, subtask_1_48.txt, subtask_1_5.txt, subtask_1_6.txt, subtask_1_7.txt, subtask_1_8.txt, subtask_1_9.txt |
Case Name |
Status |
Exec Time |
Memory |
sample_01.txt |
AC |
1 ms |
256 KB |
sample_02.txt |
AC |
1 ms |
256 KB |
sample_03.txt |
AC |
1 ms |
256 KB |
subtask_1_1.txt |
AC |
1 ms |
256 KB |
subtask_1_10.txt |
AC |
15 ms |
256 KB |
subtask_1_11.txt |
AC |
1 ms |
256 KB |
subtask_1_12.txt |
AC |
53 ms |
256 KB |
subtask_1_13.txt |
AC |
1 ms |
256 KB |
subtask_1_14.txt |
AC |
1 ms |
256 KB |
subtask_1_15.txt |
AC |
1 ms |
256 KB |
subtask_1_16.txt |
AC |
1 ms |
256 KB |
subtask_1_17.txt |
AC |
1 ms |
256 KB |
subtask_1_18.txt |
AC |
1 ms |
256 KB |
subtask_1_19.txt |
AC |
1 ms |
256 KB |
subtask_1_2.txt |
AC |
1 ms |
256 KB |
subtask_1_20.txt |
AC |
1 ms |
256 KB |
subtask_1_21.txt |
AC |
1 ms |
256 KB |
subtask_1_22.txt |
AC |
1 ms |
256 KB |
subtask_1_23.txt |
AC |
1 ms |
256 KB |
subtask_1_24.txt |
AC |
1 ms |
256 KB |
subtask_1_25.txt |
AC |
195 ms |
256 KB |
subtask_1_26.txt |
AC |
309 ms |
256 KB |
subtask_1_27.txt |
AC |
62 ms |
256 KB |
subtask_1_28.txt |
AC |
3 ms |
256 KB |
subtask_1_29.txt |
AC |
1 ms |
256 KB |
subtask_1_3.txt |
AC |
1 ms |
256 KB |
subtask_1_30.txt |
AC |
1 ms |
256 KB |
subtask_1_31.txt |
AC |
1 ms |
256 KB |
subtask_1_32.txt |
AC |
1 ms |
256 KB |
subtask_1_33.txt |
AC |
1 ms |
256 KB |
subtask_1_34.txt |
AC |
2 ms |
256 KB |
subtask_1_35.txt |
AC |
3 ms |
256 KB |
subtask_1_36.txt |
AC |
2 ms |
256 KB |
subtask_1_37.txt |
AC |
1 ms |
256 KB |
subtask_1_38.txt |
AC |
1 ms |
256 KB |
subtask_1_39.txt |
AC |
1 ms |
256 KB |
subtask_1_4.txt |
AC |
1 ms |
256 KB |
subtask_1_40.txt |
AC |
1 ms |
256 KB |
subtask_1_41.txt |
AC |
1 ms |
256 KB |
subtask_1_42.txt |
AC |
1 ms |
256 KB |
subtask_1_43.txt |
AC |
1 ms |
256 KB |
subtask_1_44.txt |
AC |
1 ms |
256 KB |
subtask_1_45.txt |
AC |
1 ms |
256 KB |
subtask_1_46.txt |
AC |
1 ms |
256 KB |
subtask_1_47.txt |
AC |
1 ms |
256 KB |
subtask_1_48.txt |
AC |
1 ms |
256 KB |
subtask_1_5.txt |
AC |
9 ms |
256 KB |
subtask_1_6.txt |
AC |
30 ms |
256 KB |
subtask_1_7.txt |
AC |
6 ms |
256 KB |
subtask_1_8.txt |
AC |
21 ms |
256 KB |
subtask_1_9.txt |
AC |
9 ms |
256 KB |