题意:
思路:
【问题分析】
有向无环图最小路径覆盖,可以转化成二分图最大匹配问题,从而用最大流解决。
【建模方法】
构造二分图,把原图每个顶点i拆分成二分图X,Y集合中的两个顶点Xi和Yi。对于原图中存在的每条边(i,j),在二分图中连接边(Xi,Yj)。然后把二分图最大匹配模型转化为网络流模型,求网络最大流。
最小路径覆盖的条数,就是原图顶点数,减去二分图最大匹配数。沿着匹配边查找,就是一个路径上的点,输出所有路径即可。
【建模分析】
对于一个路径覆盖,有如下性质:
1、每个顶点属于且只属于一个路径。
2、路径上除终点外,从每个顶点出发只有一条边指向路径上的另一顶点。
所以我们可以把每个顶点理解成两个顶点,一个是出发,一个是目标,建立二分图模型。该二分图的任何一个匹配方案,都对应了一个路径覆盖方案。如果匹配数为0,那么显然路径数=顶点数。每增加一
条匹配边,那么路径覆盖数就减少一个,所以路径数=顶点数 - 匹配数。要想使路径数最少,则应最大化匹配数,所以要求二分图的最大匹配。
注意,此建模方法求最小路径覆盖仅适用于有向无环图,如果有环或是无向图,那么有可能求出的一些环覆盖,而不是路径覆盖。
DAG的最小路径覆盖=点数-二分图最大匹配
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef unsigned int uint; 5 typedef unsigned long long ull; 6 typedef long double ld; 7 typedef pair<int,int> PII; 8 typedef pair<ll,ll> Pll; 9 typedef vector<int> VI; 10 typedef vector<PII> VII; 11 //typedef pair<ll,ll>P; 12 #define N 200010 13 #define M 200010 14 #define INF 1e9 15 #define fi first 16 #define se second 17 #define MP make_pair 18 #define pb push_back 19 #define pi acos(-1) 20 #define mem(a,b) memset(a,b,sizeof(a)) 21 #define rep(i,a,b) for(int i=(int)a;i<=(int)b;i++) 22 #define per(i,a,b) for(int i=(int)a;i>=(int)b;i--) 23 #define lowbit(x) x&(-x) 24 #define Rand (rand()*(1<<16)+rand()) 25 #define id(x) ((x)<=B?(x):m-n/(x)+1) 26 #define ls p<<1 27 #define rs p<<1|1 28 29 const ll MOD=1e9+7,inv2=(MOD+1)/2; 30 double eps=1e-6; 31 int dx[4]={-1,1,0,0}; 32 int dy[4]={0,0,-1,1}; 33 34 int head[N],vet[N],len[N],nxt[N],dis[N],num[N][2],vis[N],s,S,T,tot,n,m; 35 36 int read() 37 { 38 int v=0,f=1; 39 char c=getchar(); 40 while(c<48||57<c) {if(c=='-') f=-1; c=getchar();} 41 while(48<=c&&c<=57) v=(v<<3)+v+v+c-48,c=getchar(); 42 return v*f; 43 } 44 45 void add(int a,int b,int c) 46 { 47 nxt[++tot]=head[a]; 48 vet[tot]=b; 49 len[tot]=c; 50 head[a]=tot; 51 52 nxt[++tot]=head[b]; 53 vet[tot]=a; 54 len[tot]=0; 55 head[b]=tot; 56 } 57 58 bool bfs() 59 { 60 queue<int>q; 61 rep(i,1,s) dis[i]=-1; 62 q.push(S),dis[S]=0; 63 while(!q.empty()) 64 { 65 int u=q.front(); 66 q.pop(); 67 int e=head[u]; 68 while(e) 69 { 70 int v=vet[e]; 71 if(len[e]>0&&dis[v]==-1) 72 { 73 dis[v]=dis[u]+1; 74 q.push(v); 75 } 76 e=nxt[e]; 77 } 78 } 79 return dis[T]!=-1; 80 } 81 82 int dfs(int u,int aug) 83 { 84 if(u==T) return aug; 85 int e=head[u],val=0,flow=0; 86 while(e) 87 { 88 int v=vet[e]; 89 if(len[e]>0&&dis[v]==dis[u]+1) 90 { 91 int t=dfs(v,min(len[e],aug)); 92 if(!t) 93 { 94 e=nxt[e]; 95 continue; 96 } 97 flow+=t; 98 aug-=t; 99 len[e]-=t; 100 len[e^1]+=t; 101 if(!aug) break; 102 } 103 e=nxt[e]; 104 } 105 if(!flow) dis[u]=-1; 106 return flow; 107 } 108 109 void print(int u) 110 { 111 //printf("u=%d ",u); 112 if(u<=0||u==S) return; 113 printf("%d ",u); 114 int e=head[u]; 115 while(e) 116 { 117 int v=vet[e]; 118 if(!len[e]&&v<S) print(v-n); 119 e=nxt[e]; 120 } 121 } 122 123 int main() 124 { 125 n=read(),m=read(); 126 s=0; 127 rep(i,1,n) num[i][0]=++s; 128 rep(i,1,n) num[i][1]=++s; 129 S=++s; T=++s; 130 rep(i,1,s) head[i]=0; 131 tot=1; 132 while(m--) 133 { 134 int x=read(),y=read(); 135 add(num[x][0],num[y][1],1); 136 } 137 rep(i,1,n) add(S,num[i][0],1); 138 rep(i,1,n) add(num[i][1],T,1); 139 int ans=n; 140 while(bfs()) ans-=dfs(S,INF); 141 int e=head[T]; 142 while(e) 143 { 144 int v=vet[e]; 145 if(len[e]) 146 { 147 e=nxt[e]; 148 continue; 149 } 150 print(v-n); 151 printf(" "); 152 e=nxt[e]; 153 } 154 155 printf("%d ",ans); 156 return 0; 157 }