版权声明:本文为博主原创文章,未经博主允许也可以转载。 https://blog.csdn.net/FrankAx/article/details/82763168
洛谷2756飞行员配对
思路:二分图最大匹配。
构图:s -> i , i -> j j -> t 均为1.
Code:
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int AX = 1e3 + 6 ;
int m , n ;
int s , t ;
int tot ;
int cnt ;
int head[AX*20];
int cur[AX*20] ;
int d[AX];
int idx[AX*20];
struct Node{
int u , v , flow , next1 ;
Node( int u = 0 , int v = 0 , int flow = 0 , int next1 = 0 ):u(u),v(v),flow(flow),next1(next1){}
}G[AX*20];
void addedge( int u , int v , int w ){
G[tot] = Node( u , v , w , head[u] ) ; head[u] = tot ++ ;
G[tot] = Node( v , u , 0 , head[v] ) ; head[v] = tot ++ ;
}
bool bfs( ){
memset( d, -1 , sizeof(d) );
d[s] = 0 ;
queue<int>q ;
q.push( s ) ;
while( !q.empty() ){
int u = q.front() ;
q.pop();
for( int i = head[u] ; ~i ; i = G[i].next1 ){
int v = G[i].v ;
if( d[v] == -1 && G[i].flow ) {
d[v] = d[u] + 1 ;
q.push(v) ;
if( v == t ) return true ;
}
}
}
return ~d[t];
}
int dfs( int u , int cap ){
if( u == t ) return cap ;
int r = 0 ;
for( int i = cur[u] ; ~i ; i = G[i].next1) {
int v = G[i].v ;
if( G[i].flow && d[v] == d[u] + 1 ){
int tmp = min( G[i].flow , cap - r );
cur[u] = i ;
tmp = dfs(v,tmp);
r += tmp ;
G[i].flow -= tmp ;
G[i^1].flow += tmp ;
if( r == cap ) break;
}
}
if( !r ) d[u] -= 2 ;
return r ;
}
int Dinic( ){
int cnt = 0 ;
int tmp ;
while( bfs() ){
memcpy(cur,head,sizeof(head));
while( tmp = dfs( s, INF ) ) cnt += tmp ;
}
return cnt ;
}
int main(){
int m , n ;
scanf("%d%d",&m,&n);
int x , y ;
tot = 0 ;
memset( head , -1 , sizeof(head) ) ;
s = n + m + 1 ;
t = n + m + 2 ;
for( int i = 1 ; i <= m ; i++ ){
addedge( s , i , 1 ) ;
}
for( int i = m + 1 ; i <= n ; i++ ){
addedge( i , t , 1 ) ;
}
int num = 0 ;
while( scanf("%d%d",&x,&y) && ~x && ~y ){
addedge( x , y , 1 ) ;
idx[num++] = tot - 1 ;
}
int res = Dinic() ;
if( !res ){
puts("No Solution!");
}else{
printf("%d\n",res);
for( int i = 0 ; i < num ; i++ ){
if( G[idx[i]].flow ) {
printf("%d %d\n",G[idx[i]].u,G[idx[i]].v);
}
}
}
return 0 ;
}
洛谷2764最小路径覆盖
思路:
每个点拆成 i ,j ,n个点,如果没有边,那么最小路径覆盖就是n条边。每出现一个二分匹配就少一条边。因此最小路径覆盖= 顶点数 - 最大二分匹配。
构图:s - > i , i -> j ,j - > t
最后输出每条简单路时,只需在dfs寻增广路成功时,记录每个点所匹配的点。
Code:
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std ;
const int AX = 6e3 + 66;
int s , t ;
int head[AX];
int cur[AX] ;
int tot ;
int d[AX];
int nxt[AX];
int n , m ;
bool vis[AX];
struct Node{
int u , v , cap , next1 ;
Node( int u = 0 , int v = 0 , int cap = 0 , int next1 = 0 ):u(u),v(v),cap(cap),next1(next1){}
}G[AX*10];
void addedge( int u , int v , int w ){
G[tot] = Node( u , v , w , head[u] ) ; head[u] = tot ++ ;
G[tot] = Node( v , u , 0 , head[v] ) ; head[v] = tot ++ ;
}
bool bfs( ){
memset( d , -1 , sizeof(d) ) ;
d[s] = 0 ;
queue<int>q ;
q.push(s);
while( !q.empty() ) {
int u = q.front() ;
q.pop() ;
for( int i = head[u] ; ~i ; i = G[i].next1 ){
int v = G[i].v ;
if( d[v] == -1 && G[i].cap ){
d[v] = d[u] + 1 ;
q.push(v);
if( v == t ) return true;
}
}
}return ~d[t];
}
int dfs( int u , int cap ){
if( u == t || !cap ) return cap ;
int r = 0 ;
for( int i = cur[u] ; ~i ; i = G[i].next1 ){
int v = G[i].v ;
if( G[i].cap && d[v] == d[u] + 1 ){
int tmp = min( G[i].cap , cap - r ) ;
cur[u] = i ;
tmp = dfs( v , tmp );
if( tmp ){
nxt[u] = v ;
if( v > n ) vis[v-n] = true ;
}
r += tmp ;
G[i].cap -= tmp ;
G[i^1].cap += tmp ;
if( r == cap ) break ;
}
}
if( !r ) d[u] -= 2 ;
return r ;
}
int Dinic( ){
int cnt = 0 ;
int tmp ;
while( bfs( ) ){
memcpy( cur , head , sizeof(head) );
while( tmp = dfs( s , INF ) ) cnt += tmp ;
}
return cnt ;
}
int main(){
int x , y ;
memset( head , -1 , sizeof(head) ) ;
memset( vis , false , sizeof(vis) ) ;
scanf("%d%d",&n,&m) ;
s = 2 * n + 1 ; t = 2 * n + 2 ;
for( int i = 0 ; i < m ; i++ ){
scanf("%d%d",&x,&y);
addedge( x , y + n , 1 ) ;
}
for( int i = 1 ; i <= n ; i++ ){
addedge( s , i , 1 ) ;
}
for( int i = 1 ; i <= n ; i++ ){
addedge( i + n , t , 1 ) ;
}
int res = Dinic() ;
for( int i = 1 ; i <= n ; i++ ){
if( !vis[i] ){
printf("%d",i); int u = i ;
while( nxt[u] ){
printf(" %d",nxt[u] - n);
u = nxt[u] - n;
}printf("\n");
}
}
printf("%d\n",n - res);
return 0 ;
}