1. 程式人生 > >[BZOJ1143][CTSC2008]祭祀river

[BZOJ1143][CTSC2008]祭祀river

== 滿足 要求 class hung space 一個點 || strong

題面戳我

sol

介紹幾個基於有向無環圖(DAG)的概念:

廣義上來說,鏈是一個點集,其中任意兩點u,v,都滿足[u能到達v]+[v能到達u]=1(就是說兩個只滿足其一)

反鏈

與鏈的定義類似,就是任意兩個點都無法到達。
這個題要求的是最長反鏈
而最長反鏈等於最小鏈覆蓋 (我不會證)

最小鏈覆蓋

用最少的鏈去覆蓋整張圖,使得每個點被覆蓋至少一次(不同於最小路徑覆蓋只能覆蓋每個點一次)
而要求最小鏈覆蓋,只要先跑一次傳遞閉包(只是說得高大上一點啦,其實就是個\(Floyed\)),然後就變成了最小路徑覆蓋。最小路徑覆蓋可以直接跑二分圖最大匹配(每個點匹配一個後繼)

code

壓行壓得喪心病狂

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 105;
int gi()
{
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9'
) x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } int n,m,g[N][N],matching[N],check[N],id; bool dfs(int u) { for (int i=1;i<=n;i++) { if (!g[u][i]||check[i]==id) continue; check[i]=id; if (!matching[i]||dfs(matching[i])) return
matching[i]=u,true; } return false; } int Hungarian() { int ans=0; for (int i=1;i<=n;i++) {id++;if (dfs(i)) ans++;} return ans; } int main() { n=gi();m=gi(); for (int i=1;i<=m;i++) g[gi()][gi()]=1; for (int k=1;k<=n;k++) for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) g[i][j]|=g[i][k]&g[k][j]; return printf("%d\n",n-Hungarian()),0; }

[BZOJ1143][CTSC2008]祭祀river