传送门:点击打开链接
题意:给一个DAG模型,求最小的路径覆盖,不过这里的路径是可以重叠的。
思路:我们用二分图求的最小路径覆盖的路径是不能有相交的。
所以我们先去遍历一遍DAG模型,对于u点,假如能通过有向边能到达v点,那么就在u和v中间连一条有向边。
对于这个新图我们再用经典的拆点法去跑最小路径覆盖,这题就算是做完了。
在通过DFS建立图的时候,要注意打标记,不然枚举量会非常大。
#include<map> #include<set> #include<cmath> #include<ctime> #include<stack> #include<queue> #include<cstdio> #include<cctype> #include<bitset> #include<string> #include<vector> #include<cstring> #include<iostream> #include<algorithm> #include<functional> #define fuck(x) cout<<"["<<x<<"]" #define FIN freopen("input.txt","r",stdin) #define FOUT freopen("output.txt","w+",stdout) //#pragma comment(linker, "/STACK:102400000,102400000") using namespace std; typedef long long LL; const int MX = 1e3 + 5; const int MS = 5e5 + 5; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int Head[MX], erear; struct Edge { int v, nxt; } E[MS]; void edge_init() { erear = 0; memset(Head, -1, sizeof(Head)); } void edge_add(int u, int v) { E[erear].v = v; E[erear].nxt = Head[u]; Head[u] = erear++; } int match[MX]; bool vis[MX]; bool DFS(int u) { for(int i = Head[u]; ~i; i = E[i].nxt) { int v = E[i].v; if(!vis[v]) { vis[v] = 1; if(match[v] == -1 || DFS(match[v])) { match[v] = u; return 1; } } } return 0; } int BM(int n) { int res = 0; memset(match, -1, sizeof(match)); for(int u = 1; u <= n; u++) { memset(vis, 0, sizeof(vis)); if(DFS(u)) res++; } return res; } int n, m; int flag[MX]; bool G[MX][MX]; void DFS2(int now, int nxt) { flag[nxt] = now; edge_add(now, nxt + n); for(int v = 1; v <= n; v++) { if(flag[v] != now && G[nxt][v]) DFS2(now, v); } } int main() { //FIN; while(~scanf("%d%d", &n, &m), n) { edge_init(); memset(G, 0, sizeof(G)); memset(flag, 0, sizeof(flag)); for(int i = 1; i <= m; i++) { int u, v; scanf("%d%d", &u, &v); G[u][v] = 1; } for(int i = 1; i <= n; i++) { for(int v = 1; v <= n; v++) { if(G[i][v]) DFS2(i, v); } } printf("%d\n", n - BM(n)); } return 0; }