[Violet 4] 毕业旅行
2718: [Violet 4]毕业旅行
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 672 Solved: 389
[Submit][Status][Discuss]
Description
Input
Output
最多可选多少景点
Sample Input
7 6
1 2
2 3
5 4
4 3
3 6
6 7
1 2
2 3
5 4
4 3
3 6
6 7
Sample Output
2
HINT
首先有一个结论是:最长反链大小 = 最小路径覆盖数。
这个具体证明我也不太会,只知道首先 最长反链肯定 <= 最小路径覆盖 (考虑反链的定义),然后再xxxx就出来了(逃
最小路径覆盖就是经典网络流问题了2333 (有一个叫 组合数学 的题貌似就是这个道理)
#include<bits/stdc++.h> #define ll long long #define pb push_back using namespace std; const int maxn=505; vector<int> g[maxn]; struct lines{ int to,flow,cap; }l[maxn*maxn]; int t=-1,S,T,d[maxn],cur[maxn]; bool v[maxn]; inline void add(int from,int to,int cap){ l[++t]=(lines){to,0,cap},g[from].pb(t); l[++t]=(lines){from,0,0},g[to].pb(t); } inline bool BFS(){ queue<int> q; memset(v,0,sizeof(v)); q.push(S),v[S]=1,d[S]=0; int x; lines e; while(!q.empty()){ x=q.front(),q.pop(); for(int i=g[x].size()-1;i>=0;i--){ e=l[g[x][i]]; if(e.flow<e.cap&&!v[e.to]){ v[e.to]=1,d[e.to]=d[x]+1; q.push(e.to); } } } return v[T]; } int dfs(int x,int A){ if(x==T||!A) return A; int flow=0,f,sz=g[x].size(); for(int &i=cur[x];i<sz;i++){ lines &e=l[g[x][i]]; if(d[x]==d[e.to]-1&&(f=dfs(e.to,min(e.cap-e.flow,A)))){ A-=f,flow+=f; e.flow+=f,l[g[x][i]^1].flow-=f; if(!A) break; } } return flow; } inline int max_flow(){ int an=0; while(BFS()){ memset(cur,0,sizeof(cur)); an+=dfs(S,1<<30); } return an; } int n,m,uu,vv; bool G[205][205]; inline void build(){ for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(G[i][k]&&G[k][j]) G[i][j]=1; S=0,T=n*2+1; for(int i=1;i<=n;i++) add(S,i,1),add(i+n,T,1); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(G[i][j]) add(i,j+n,1); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d",&uu,&vv),G[uu][vv]=1; build(),printf("%d\n",n-max_flow()); return 0; }
我爱学习,学习使我快乐