大致题意:给出一个DAG,问能否用n+1条可重复路径覆盖整个图。
最小有重复路径覆盖问题,先传递闭包,转化成无重复路径覆盖问题。
然后把原图每个点拆成两个点建立二分图,然后用原图点数 − - −最大匹配数就是答案。
如果可以覆盖就输出 A K AK AK,否则二分一个最大可行权值 m i d mid mid,大于 m i d mid mid的点连一个 i − > i i -> i i−>i的边,表示忽略这个点,然后照常建图即可。
#define others
#ifdef poj
#include
#include
#include
#include
#include
#include
#include
#include
#include
#endif // poj
#ifdef others
#include
#include
#include
#endif // others
//#define file
#define all(x) x.begin(), x.end()
using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;
#define eps 1e-8
const double pi = acos(-1.0);
typedef long long LL;
typedef long long DLL;
typedef unsigned long long ULL;
void umax(LL &a, LL b) {
a = max(a, b);
}
void umin(LL &a, LL b) {
a = min(a, b);
}
int dcmp(double x) {
return fabs(x) <= eps?0:(x > 0?1:-1);
}
void file() {
freopen("data_in.txt", "r", stdin);
freopen("data_out.txt", "w", stdout);
}
DLL mod = 1e9;
DLL Pow(DLL a,DLL b) {
DLL res=1;
a%=mod;
for(; b; b>>=1) {
if(b&1)res=res*a%mod;
a=a*a%mod;
}
return res;
}
//
//void print(DLL x) {
// if(x < 0) {
// x = -x;
// putchar('-');
// }
// if(x > 9) print(x/10);
// putchar(x%10 + '0');
//}
//#define iostart
//#define iostart
#define pb(x) push_back(x)
namespace solver {
const int maxn = 510;
int n, m;
int g[maxn][maxn];
vector<int> G[maxn];
int link[maxn], vis[maxn];
int v[maxn];
bool dfs(int u) {
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if(!vis[v]) {
vis[v] = 1;
if(link[v] == -1 || dfs(link[v])) {
link[v] = u;
return 1;
}
}
}
return 0;
}
int gao() {
int ans = 0;
memset(link, -1, sizeof link);
for(int i = 1; i <= m; i++) {
memset(vis, 0, sizeof vis);
if(dfs(i))
ans++;
}
return ans;
}
bool check_val(int x) {
for (int i = 1; i <= m; i++) {
G[i].clear();
}
for (int i = 1; i <= m; i++){
if (v[i] > x) {
G[i].push_back(i);
}
for (int j = 1; j <= m; j++){
if (g[i][j]) {
G[i].push_back(j);
// cout << i << " xx " << j << endl;
}
}
}
int match = gao();
// cout << x << " " << m - match << endl;
return m - match <= n + 1;
}
vector<int> hash_val;
void solve() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++){
int val, k;
scanf("%d%d", &val, &k);
v[i] = val;
hash_val.push_back(val);
while (k--) {
int to;
scanf("%d", &to);
g[i][to] = 1;
}
}
for (int k = 1; k <= m; k++) {
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= m; j++) {
if (g[i][k] && g[k][j]) {
g[i][j] = 1;
}
}
}
}
sort(all(hash_val));
hash_val.erase(unique(all(hash_val)), hash_val.end());
int L = 0, R = (int)hash_val.size() - 2, M;
while (L + 4 < R) {
M = L + R >> 1;
if (check_val(hash_val[M])) {
L = M;
} else {
R = M;
}
}
for (; L < R; L++) {
if (!check_val(hash_val[L]))
break;
}
if (check_val(hash_val[L])) {
puts("AK");
} else {
printf("%d\n", hash_val[L]);
}
}
}
int main() {
#ifdef iostart
ios::sync_with_stdio(0);
cin.tie(0);
#endif // iostart
// file();
solver::solve();
return 0;
}
由于传递闭包之后是一个稠密图,所以可以用bitset去优化匈牙利算法。
#define others
#ifdef poj
#include
#include
#include
#include
#include
#include
#include
#include
#include
#endif // poj
#ifdef others
#include
#include
#include
#endif // others
//#define file
#define all(x) x.begin(), x.end()
using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;
#define eps 1e-8
const double pi = acos(-1.0);
typedef long long LL;
typedef long long DLL;
typedef unsigned long long ULL;
void umax(LL &a, LL b) {
a = max(a, b);
}
void umin(LL &a, LL b) {
a = min(a, b);
}
int dcmp(double x) {
return fabs(x) <= eps?0:(x > 0?1:-1);
}
void file() {
freopen("data_in.txt", "r", stdin);
freopen("data_out.txt", "w", stdout);
}
DLL mod = 1e9;
DLL Pow(DLL a,DLL b) {
DLL res=1;
a%=mod;
for(; b; b>>=1) {
if(b&1)res=res*a%mod;
a=a*a%mod;
}
return res;
}
//
//void print(DLL x) {
// if(x < 0) {
// x = -x;
// putchar('-');
// }
// if(x > 9) print(x/10);
// putchar(x%10 + '0');
//}
//#define iostart
//#define iostart
#define pb(x) push_back(x)
namespace solver {
const int maxn = 510;
int n, m;
int g[maxn][maxn];
int a[maxn][maxn/32+1], b[maxn][maxn/32+1];
int link[maxn], vis[maxn];
int q[maxn];
typedef int U;
int tot = m >> 5;
inline void set1(U v[],int x){v[x>>5]|=1U<<(x&31);}
inline void flip(U v[],int x){v[x>>5]^=1U<<(x&31);}
bool dfs(int u) {
for (int i = 0; i <= tot; i++) {
for (;;) {
U o = b[u][i]&vis[i];
if (!o) break;
int y = i<<5|__builtin_ctz(o);
flip(vis, y);
if (!link[y] || dfs(link[y])) return link[y]=u, 1;
}
}
return 0;
}
int gao() {
for (int i = 1; i <= m; i++) link[i] = 0;
int ans = 0;
for(int i = 1; i <= m; i++) {
for (int j = 1; j <= m; j++) set1(vis, j);
if(dfs(i)) ans++;
}
return ans;
}
bool check_val(int x) {
for (int i = 1; i <= m; i++){
for (int j = 0; j <= tot; j++) {
b[i][j] = a[i][j];
}
}
for (int i = 1; i <= m; i++) {
if (q[i] > x) {
set1(b[i], i);
}
}
for (int i = 1; i <= m; i++) link[i] = 0;
int match = gao();
return m - match <= n + 1;
}
vector<int> hash_val;
void solve() {
scanf("%d%d", &n, &m);
tot = m >> 5;
for (int i = 1; i <= m; i++){
int val, k;
scanf("%d%d", &val, &k);
q[i] = val;
hash_val.push_back(val);
while (k--) {
int to;
scanf("%d", &to);
g[i][to] = 1;
}
}
for (int k = 1; k <= m; k++) {
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= m; j++) {
if (g[i][k] && g[k][j]) {
g[i][j] = 1;
}
}
}
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= m; j++) {
if (g[i][j])
set1(a[i], j);
}
}
sort(all(hash_val));
hash_val.erase(unique(all(hash_val)), hash_val.end());
int L = 0, R = (int)hash_val.size() - 2, M;
while (L + 4 < R) {
M = L + R >> 1;
if (check_val(hash_val[M])) {
L = M;
} else {
R = M;
}
}
for (; L < R; L++) {
if (!check_val(hash_val[L]))
break;
}
if (check_val(hash_val[L])) {
puts("AK");
} else {
printf("%d\n", hash_val[L]);
}
}
}
int main() {
#ifdef iostart
ios::sync_with_stdio(0);
cin.tie(0);
#endif // iostart
// file();
solver::solve();
return 0;
}