JZOJ4760. 同桌的你

本文介绍了一种解决特定图论问题的方法——在环套树模型下寻找最优匹配策略,使得最多的个体与其满意的伙伴配对,并在此基础上尽可能多地实现不同性别的配对。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意

给定n个人,以及他们的性别和他们满意的同桌(每人只有一个满意同桌)。现在要把这n个人两两分配成同桌,问最多有多少对同桌中至少有一个人的同桌是满意的同桌,在满足这个的前提最多有多少对满足要求的同桌的性别是不同的。
T组数据。

Data Constraint
n106,T3

题解

可以注意到,这题其实是一个环套树模型。
假如是一棵树我们可以怎么做?显然可以DP。设f[i]表示i和它儿子匹配的最优匹配数,g[i]表示i不与儿子匹配的最优方案数。转移比较显然。
现在剩下环套树的问题。实际上,我们任选一条环上的边,将它删去,跑一遍DP。唯一可能比它有的情况是保留这条边,删去一条与它相邻的环边。所以跑两次DP取最优值即可。正确性:如果当前删除的这条边在最优解里面,那么与它相邻的环边一定不在最优解里面。
时间复杂度:O(n)

SRC

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std ;

#define N 1000000 + 1
#define fir first
#define sec second
typedef pair < int , int > Note ;

int Node[2*N] , Next[2*N] , Head[N] , tot ;

Note f[N] , g[N] , Rec[N] ;
int from[N] ;

bool vis[N] ;
int a[N] , b[N] ;
int D[N] ;
int Case , n ;
int ans1 , ans2 , origin , top ;
Note Ans ;

Note operator + ( Note a , Note b ) {
    Note ret( a.fir + b.fir , a.sec + b.sec ) ;
    return ret ;
}

Note operator - ( Note a , Note b ) {
    Note ret( a.fir - b.fir , a.sec - b.sec ) ;
    return ret ;
}

void link( int u , int v ) {
    Node[++tot] = v ;
    Next[tot] = Head[u] ;
    Head[u] = tot ;
}

void BFS( int st ) {
    int i = 0 , j = 1 ;
    D[1] = st ;
    vis[st] = 1 ;
    while ( i < j ) {
        i ++ ;
        int now = D[i] ;
        for (int p = Head[now] ; p ; p = Next[p] ) {
            if ( Node[p] == st ) continue ;
            vis[Node[p]] = 1 ;
            D[++j] = Node[p] ;
        }
    }
    D[0] = j ;
}

void DP() {
    memset( f , 0 , sizeof(f) ) ;
    memset( g , 0 , sizeof(g) ) ;
    memset( from , 0 , sizeof(from) ) ;
    for (int i = D[0] ; i ; i -- ) {
        int x = D[i] ;
        for (int p = Head[x] ; p ; p = Next[p] ) {
            if ( Node[p] == D[1] ) continue ;
            g[x] = g[x] + max( f[Node[p]] , g[Node[p]] ) ;
        }
        for (int p = Head[x] ; p ; p = Next[p] ) {
            if ( Node[p] == D[1] ) continue ;
            Note tp( g[Node[p]].fir + 1 , g[Node[p]].sec + (b[x] ^ b[Node[p]]) ) ;
            if ( g[x] - max( f[Node[p]] , g[Node[p]] ) + tp > f[x] ) {
                f[x] = g[x] - max( f[Node[p]] , g[Node[p]] ) + tp ;
                from[x] = Node[p] ;
            }
        }
    }
    if ( max( f[D[1]] , g[D[1]] ) > Ans ) {
        top = origin ;
        Ans = max( f[D[1]] , g[D[1]] ) ;
        for (int i = 1 ; i <= D[0] ; i ++ ) {
            int x = D[i] ;
            if ( f[x] > g[x] && from[x] ) {
                from[from[x]] = 0 ;
                Rec[++top] = make_pair( x , from[x] ) ;
            }
        }
    }

}

int main() {
    scanf( "%d" , &Case ) ;
    while ( Case -- ) {
        ans1 = ans2 = tot = 0 ;
        memset( vis , 0 , sizeof(vis) ) ;
        memset( Head , 0 , sizeof(Head) ) ;
        scanf( "%d" , &n ) ;
        for (int i = 1 ; i <= n ; i ++ ) {
            scanf( "%d%d" , &a[i] , &b[i] ) ;
            b[i] -- ;
            link( a[i] , i ) ;
        }
        top = 0 ;
        for (int i = 1 ; i <= n ; i ++ ) {
            if ( vis[i] ) continue ;
            int x = i ;
            for (; !vis[x] ; x = a[x] ) vis[x] = 1 ;
            Ans = make_pair( 0 , 0 ) ;
            origin = top ;
            BFS(x) ;
            DP() ;
            BFS(a[x]) ;
            DP() ;
            ans1 += Ans.fir , ans2 += Ans.sec ;
        }
        printf( "%d %d\n" , ans1 , ans2 ) ;
        for (int i = 1 ; i <= ans1 ; i ++ ) printf( "%d %d\n" , Rec[i].fir , Rec[i].sec ) ;
    }
    return 0 ;
}

以上.

内容概要:本文档详细介绍了基于MATLAB实现多目标差分进化(MODE)算法进行无人机三维路径规划的项目实例。项目旨在提升无人机在复杂三维环境中路径规划的精度、实时性、多目标协调处理能力、障碍物避让能力和路径平滑性。通过引入多目标差分进化算法,项目解决了传统路径规划算法在动态环境和多目标优化中的不足,实现了路径长度、飞行安全距离、能耗等多个目标的协调优化。文档涵盖了环境建模、路径编码、多目标优化策略、障碍物检测与避让、路径平滑处理等关键技术模块,并提供了部分MATLAB代码示例。 适合人群:具备一定编程基础,对无人机路径规划和多目标优化算法感兴趣的科研人员、工程师和研究生。 使用场景及目标:①适用于无人机在军事侦察、环境监测、灾害救援、物流运输、城市管理等领域的三维路径规划;②通过多目标差分进化算法,优化路径长度、飞行安全距离、能耗等多目标,提升无人机任务执行效率和安全性;③解决动态环境变化、实时路径调整和复杂障碍物避让等问题。 其他说明:项目采用模块化设计,便于集成不同的优化目标和动态环境因素,支持后续算法升级与功能扩展。通过系统实现和仿真实验验证,项目不仅提升了理论研究的实用价值,还为无人机智能自主飞行提供了技术基础。文档提供了详细的代码示例,有助于读者深入理解和实践该项目。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值