Solution [CTSC2008]祭祀
题目大意:求有向图最长反链,输出一种合法方案,以及一个点是否出现在至少一种合法方案里面
二分图
分析:
最长反链不好求,做个\(Floyd\)传递闭包,然后就是求最大点独立集了
然后\(3min\)淦了\(CTSC\)题?naive,毒瘤SPJ让你输出方案
第二问我们先找一个最大匹配,从左侧点的选没有被匹配的跑\(dfs\),每次从左到有走非匹配边,从右往左走匹配边。然后一路走一路标记,左边没有被标记过的点和右边被标记过的点就是最大点独立集
证明显然,匈牙利树不好想可以转成网络流
然后第三问,我们依次枚举删掉每一个点,如果删掉这个点之后答案减小了\(1\)那么这个点可能在最长反链中否则不可能
#include <cstdio> #include <cstring> #include <vector> using namespace std; const int maxn = 256,maxm = maxn * maxn; vector<int> G[maxn]; inline void addedge(int from,int to){G[from].push_back(to);} int n,m,ans,ban[maxn],match[maxn],vis[maxn],f[maxn][maxn],left[maxn],right[maxn]; inline bool find(int u){ if(ban[u])return false; for(int v : G[u]) if(!ban[v] && !vis[v]){ vis[v] = 1; if(!match[v] || find(match[v])){ match[v] = u; return true; } } return false; } inline void floyd(){ for(int k = 1;k <= n;k++) for(int i = 1;i <= n;i++) for(int j = 1;j <= n;j++) f[i][j] |= (f[i][k] && f[k][j]); } inline void build(){ for(int u = 1;u <= n;u++) for(int v = 1;v <= n;v++) if(f[u][v])addedge(u,v); } inline void dfs(int u){ if(left[u])return; left[u] = 1; for(int v : G[u]) if(!right[v])right[v] = 1,dfs(match[v]); } int main(){ scanf("%d %d",&n,&m);ans = n; for(int u,v,i = 1;i <= m;i++) scanf("%d %d",&u,&v),f[u][v] = 1; floyd(); build(); for(int i = 1;i <= n;i++) memset(vis,0,sizeof(vis)),ans -= find(i); printf("%d\n",ans); memset(vis,0,sizeof(vis)); for(int i = 1;i <= n;i++) vis[match[i]] = 1; for(int i = 1;i <= n;i++) if(!vis[i])dfs(i); for(int i = 1;i <= n;i++) printf("%d",left[i] && !right[i]); printf("\n"); for(int gg = 1;gg <= n;gg++){ memset(match,0,sizeof(match)); memset(ban,0,sizeof(ban)); int tmp = 0; for(int i = 1;i <= n;i++) if(f[i][gg] || f[gg][i] || i == gg)ban[i] = 1; else tmp++; for(int i = 1;i <= n;i++) memset(vis,0,sizeof(vis)),tmp -= find(i); printf("%d",tmp == ans - 1); } return 0; }