[BZOJ1143][CTSC2008]祭祀river
阿新 • • 發佈:2018-01-22
== 滿足 要求 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