题意:
Y族居住地水系是一个由岔口和河道组成的网络。每条河道连接着两个岔口,并且水在河道内按照一个固定的方向流动。水系中不会有环流。由于人数众多的原因,Y族的祭祀活动会在多个岔口上同时举行。Y族人认为,如果水流可以从一个祭祀点流到另外一个祭祀点,那么祭祀就会失去它神圣的意义。求保持祭祀神圣性的基础上祭祀的地点数目的最大值。
题解:
利用各种性质。首先,题目的模型被称为最长反链,即在有向无环图中求一个点集使其两两不可达。Dilworth定理:最长反链长度=最小链覆盖(用最少的链覆盖所有节点)(证明:http://vfleaking.blog.163.com/blog/static/1748076342012918105514527/%vfk大神然而我看不懂)。求最小链覆盖的方法:建一个二分图,如果点a、b可达,则将左边的a与右边的边相连,求最大独立集。然后又有最大独立集=点数n(指二分图的半边的点数)-二分图最大匹配。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <queue> 5 #define INF 0x3fffffff 6 #define inc(i,j,k) for(int i=j;i<=k;i++) 7 using namespace std; 8 9 int n,m,a[200][200],s,t; 10 struct e{int t,c,n;}; e es[100000]; int ess,g[1000]; 11 inline void pe(int f,int t,int c){ 12 es[++ess]=(e){t,c,g[f]};g[f]=ess;es[++ess]=(e){f,0,g[t]};g[t]=ess; 13 } 14 void init(){ess=-1; memset(g,-1,sizeof(g));} 15 queue <int> q; int h[1000]; 16 bool bfs(int s,int t){ 17 while(! q.empty())q.pop(); memset(h,-1,sizeof(h)); h[s]=0; q.push(s); 18 while(! q.empty()){ 19 int x=q.front(); q.pop(); 20 for(int i=g[x];i!=-1;i=es[i].n)if(es[i].c&&h[es[i].t]==-1)h[es[i].t]=h[x]+1,q.push(es[i].t); 21 } 22 if(h[t]==-1)return 0;else return 1; 23 } 24 int dfs(int x,int t,int f){ 25 if(x==t)return f; int used=0; 26 for(int i=g[x];i!=-1;i=es[i].n)if(es[i].c&&h[es[i].t]==h[x]+1){ 27 int w=dfs(es[i].t,t,min(f,es[i].c)); 28 es[i].c-=w; es[i^1].c+=w; used+=w; f-=w; if(f==0)return used; 29 } 30 if(used==0)h[x]=-1; return used; 31 } 32 int dinic(int s,int t){int ans=0; while(bfs(s,t))ans+=dfs(s,t,INF); return ans;}; 33 int main(){ 34 scanf("%d%d",&n,&m); memset(a,0,sizeof(a)); 35 inc(i,1,m){int a1,b1; scanf("%d%d",&a1,&b1); a[a1][b1]=1;} 36 inc(k,1,n)inc(i,1,n)inc(j,1,n)a[i][j]|=a[i][k]&a[k][j]; 37 s=0; t=n+n+1; init(); 38 inc(i,1,n)pe(s,i,1),pe(i+n,t,1); 39 inc(i,1,n)inc(j,1,n)if(a[i][j])pe(i,j+n,1); 40 printf("%d",n-dinic(s,t)); 41 }
20160701