1. 程式人生 > >2018.10.11 NOIP訓練 沒有上司的舞會(最長反鏈)

2018.10.11 NOIP訓練 沒有上司的舞會(最長反鏈)

傳送門 最長反鏈板題。

直接floyd傳遞閉包之後求匹配就行了。 程式碼:

#include<bits/stdc++.h>
#define N 505
#define M 100005
#define inf 0x3f3f3f3f
using namespace std;
int n,m,s,t,cnt=0,first[N],d[N];
bool mp[N][N];
struct Node{int v,next,c;}e[M];
inline void add(int u,int v,int c){e[cnt].v=v,e[cnt].c=c,e[cnt].next=first[u],first[
u]=cnt++;} inline bool bfs(){ queue<int>q; memset(d,-1,sizeof(d)); q.push(s),d[s]=0; while(!q.empty()){ int x=q.front(); q.pop(); for(int i=first[x];~i;i=e[i].next){ int v=e[i].v; if(d[v]!=-1||e[i].c<=0)continue; d[v]
=d[x]+1; if(v==t)return true; q.push(v); } } return false; } inline int dfs(int x,int f){ if(x==t||!f)return f; int flow=f; for(int i=first[x];~i;i=e[i].next){ int v=e[i].v; if(flow&&d[v]==d[x]+1&&e[i].c>0){ int
tmp=dfs(v,min(flow,e[i].c)); if(!tmp)d[v]=-1; e[i].c-=tmp,e[i^1].c+=tmp,flow-=tmp; } } return f-flow; } inline int read(){ int ans=0; char ch=getchar(); while(!isdigit(ch))ch=getchar(); while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar(); return ans; } int main(){ memset(first,-1,sizeof(first)),cnt=0; memset(mp,false,sizeof(mp)); n=read(),m=read(),s=0,t=n*2+1; for(int i=1;i<=m;++i)mp[read()][read()]=true; for(int k=1;k<=n;++k) for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) mp[i][j]|=(mp[i][k]&mp[k][j]); for(int u=1;u<=n;++u){ add(s,u,1),add(u,s,0),add(u+n,t,1),add(t,u+n,0); for(int v=1;v<=n;++v){ if(!mp[u][v])continue; add(u,v+n,1),add(v+n,u,0); } } int ans=0; while(bfs())ans+=dfs(s,inf); cout<<n-ans; return 0; }