【codeforces】739D. Recover a functional graph【最大流实现匹配】

题目链接:【codeforces】739D. Recover a functional graph

其实就是一个匹配问题,先枚举最大的那些”x ?”放在哪个环上,那么接下来哪些地方是一定要填的都已经知道了,还没有填的地方我们就用匹配来实现。构造方案比较简单,肯定是链只从同样大小的环中随便选一个,然后再选一个点连出来,然后确定最长的树链,剩下的深度为 i 的就指向深度为i1的树链上的点即可,深度 0 就是选出的环上的点。

PS TLE115 后死活查不出来,最后把 isap 换成了之前一直用的版本就过了……新版本好像很多漏洞,赶紧删……

#include <bits/stdc++.h>
using namespace std ;

#define clr( a , x ) memset ( a , x , sizeof a )

typedef pair < int , int > pii ;

const int MAXN = 1005 ;
const int MAXE = 1000005 ;
const int INF = 0x3f3f3f3f ;

struct Edge {
    int v , c , n ;
    Edge () {}
    Edge ( int v , int c , int n ) : v ( v ) , c ( c ) , n ( n ) {}
} ;

int H[MAXN] , cntE ;
Edge E[MAXE] ;
int d[MAXN] , gap[MAXN] , cur[MAXN] , pre[MAXN] ;
int s , t , nv , flow ;
int n ;

int disc[MAXN] , sizc[MAXN] ;
int tree[MAXN][MAXN] ;
vector < int > cir[MAXN] ;
int nolim[MAXN] ;
int used[MAXN] ;
int siz[MAXN] ;
int nxt[MAXN] ;
int has[MAXN] ;
pii pos[MAXN] ;

void addedge ( int u , int v , int c ) {
    E[cntE] = Edge ( v , c , H[u] ) ;
    H[u] = cntE ++ ;
    E[cntE] = Edge ( u , 0 , H[v] ) ;
    H[v] = cntE ++ ;
}

void rev_bfs () {
    clr ( d , -1 ) ;
    clr ( gap , 0 ) ;
    queue < int > q ;
    for ( q.push ( t ) , gap[d[t] = 0] = 1 ; !q.empty () ; q.pop () ) {
        for ( int u = q.front () , i = H[u] ; ~i ; i = E[i].n ) {
            int v = E[i].v ;
            if ( d[v] == -1 ) {
                gap[d[v] = d[u] + 1] ++ ;
                q.push ( v ) ;
            }
        }
    }
}

int isap () {
    memcpy ( cur , H , sizeof cur ) ;
    flow = 0 ;
    rev_bfs () ;
    int u = pre[s] = s , i ;
    while ( d[s] < nv ) {
        if ( u == t ) {
            int f = INF ;
            for ( i = s ; i != t ; i = E[cur[i]].v ) {
                if ( f > E[cur[i]].c ) f = E[cur[u = i]].c ;
            }
            flow += f ;
            for ( i = s ; i != t ; i = E[cur[i]].v ) {
                E[cur[i]].c -= f ;
                E[cur[i] ^ 1].c += f ;
            }
        }
        for ( i = cur[u] ; ~i ; i = E[i].n ) if ( E[i].c && d[u] == d[E[i].v] + 1 ) break ;
        if ( ~i ) {
            cur[u] = i ;
            pre[E[i].v] = u ;
            u = E[i].v ;
        } else {
            if ( 0 == -- gap[d[u]] ) break ;
            int minv = nv ;
            for ( int i = H[u] ; ~i ; i = E[i].n ) {
                int v = E[i].v ;
                if ( E[i].c && minv > d[v] ) {
                    minv = d[v] ;
                    cur[u] = i ;
                }
            }
            d[u] = minv + 1 ;
            gap[d[u]] ++ ;
            u = pre[u] ;
        }
    }
    return flow ;
}

int get () {
    char s[5] ;
    scanf ( "%s" , s ) ;
    if ( s[0] == '?' ) return -1 ;
    int x ;
    sscanf ( s , "%d" , &x ) ;
    return x ;
}

void print () {
    clr ( used , 0 ) ;
    for ( int i = H[s] ; ~i ; i = E[i].n ) if ( E[i].c == 0 ) {
        int u = E[i].v ;
        for ( int j = H[u] ; ~j ; j = E[j].n ) if ( E[j].c == 0 ) {
            int v = E[j].v ;
            if ( v <= n + n ) cir[v - n].push_back ( u ) ;
            else {
                int x = pos[v].first , y = pos[v].second ;
                tree[x][y] = u ;
            }
        }
    }
    for ( int i = 1 ; i <= n ; ++ i ) if ( has[i] ) {
        tree[i][0] = cir[i][0] ;
        for ( int j = 1 ; j <= siz[i] ; ++ j ) {
            used[tree[i][j]] = 1 ;
            nxt[tree[i][j]] = tree[i][j - 1] ;
        }
        for ( int j = 0 ; j < cir[i].size () ; ++ j ) {
            used[cir[i][j]] = 1 ;
        }
        int now = 0 ;
        for ( int j = 0 ; j < cir[i].size () ; ++ j ) {
            used[cir[i][j]] = 1 ;
            if ( j == now ) nxt[cir[i][j]] = cir[i][j + i - 1] , now += i ;
            else nxt[cir[i][j]] = cir[i][j - 1] ;
        }
    }
    for ( int i = 1 ; i <= n ; ++ i ) if ( !used[i] ) {
        if ( disc[i] == -1 ) {
            if ( sizc[i] == -1 ) nxt[i] = i ;
            else nxt[i] = cir[sizc[i]][0] ;
        } else {
            if ( sizc[i] == -1 ) {
                if ( disc[i] == 0 ) nxt[i] = i ;
                else {
                    for ( int j = 1 ; j <= n ; ++ j ) {
                        if ( tree[j][disc[i] - 1] ) {
                            nxt[i] = tree[j][disc[i] - 1] ;
                            break ;
                        }
                    }
                }
            } else nxt[i] = tree[sizc[i]][disc[i] - 1] ;
        }
    }
    for ( int i = 1 ; i <= n ; ++ i ) {
        printf ( "%d%c" , nxt[i] , i < n ? ' ' : '\n' ) ;
    }
}

int check () {
    cntE = 0 ;
    clr ( H , -1 ) ;
    s = 0 ;
    t = n + n + n + 1 ;
    nv = t + 1 ;
    int L = 0 , R = 0 ;
    for ( int i = 1 ; i <= n ; ++ i ) if ( !nolim[i] ) {
        if ( disc[i] == -1 || sizc[i] == -1 ) {
            addedge ( s , i , 1 ) ;
            ++ L ;
        }
    }
    int tot = n + n ;
    for ( int i = 1 ; i <= n ; ++ i ) if ( has[i] ) {
        if ( cir[i].size () % i || !cir[i].size () ) {
            addedge ( n + i , t , i - cir[i].size () % i ) ;
            R += i - cir[i].size () % i ;
            if ( R > L ) return 0 ;
            for ( int j = 1 ; j <= n ; ++ j ) {
                if ( disc[j] == -1 && sizc[j] == -1 ) {
                    addedge ( j , n + i , 1 ) ;
                } else if ( disc[j] == -1 && sizc[j] == i ) {
                    addedge ( j , n + i , 1 ) ;
                } else if ( disc[j] == 0 && sizc[j] == -1 ) {
                    addedge ( j , n + i , 1 ) ;
                }
            }
        }
        for ( siz[i] = n ; siz[i] >= 1 ; -- siz[i] ) if ( tree[i][siz[i]] ) break ;
        for ( int j = 1 ; j <= siz[i] ; ++ j ) if ( !tree[i][j] ) {
            ++ tot ;
            ++ R ;
            if ( R > L ) return 0 ;
            pos[tot] = pii ( i , j ) ;
            addedge ( tot , t , 1 ) ;
            for ( int k = 1 ; k <= n ; ++ k ) if ( !nolim[k] ) {
                if ( disc[k] == -1 && sizc[k] == -1 ) {
                    addedge ( k , tot , 1 ) ;
                } else if ( disc[k] == -1 && sizc[k] == i ) {
                    addedge ( k , tot , 1 ) ;
                } else if ( disc[k] == j && sizc[k] == -1 ) {
                    addedge ( k , tot , 1 ) ;
                }
            }
        }
    }
    isap () ;
    if ( flow < R ) return 0 ;
    print () ;
    return 1 ;
}

void solve () {
    clr ( tree , 0 ) ;
    for ( int i = 1 ; i <= n ; ++ i ) {
        cir[i].clear () ;
        has[i] = 0 ;
        nolim[i] = 0 ;
    }
    int maxv = 0 , nocir = 1 ;
    for ( int i = 1 ; i <= n ; ++ i ) {
        disc[i] = get () ;
        sizc[i] = get () ;
        if ( sizc[i] >= 0 ) has[sizc[i]] = 1 , nocir = 0 ;
        if ( disc[i] >= 0 && sizc[i] >= 0 ) {
            maxv = max ( maxv , disc[i] ) ;
            if ( disc[i] == 0 ) cir[sizc[i]].push_back ( i ) ;
            else tree[sizc[i]][disc[i]] = i ;
        }
    }
    for ( int i = 1 ; i <= n ; ++ i ) {
        if ( disc[i] > maxv && sizc[i] == -1 ) {
            nolim[i] = 1 ;
        }
    }
    if ( !nocir ) {
        for ( int i = 1 ; i <= n ; ++ i ) if ( has[i] ) {
            for ( int j = 1 ; j <= n ; ++ j ) if ( nolim[j] ) {
                tree[i][disc[j]] = j ;
            }
            if ( check () ) return ;
            for ( int j = 1 ; j <= n ; ++ j ) if ( nolim[j] ) {
                tree[i][disc[j]] = 0 ;
            }
        }
    } else {
        has[1] = 1 ;
        for ( int j = 1 ; j <= n ; ++ j ) if ( nolim[j] ) {
            tree[1][disc[j]] = j ;
        }
        if ( check () ) return ;
    }
    printf ( "-1\n" ) ;
}

int main () {
    while ( ~scanf ( "%d" , &n ) ) solve () ;
    return 0 ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值