Sicily 1794. Missiles

本文探讨了一种在复杂图论背景下,通过应用佛洛依德算法和匈牙利算法解决国家间导弹防御策略的问题。具体而言,文章通过实例展示了如何计算任意两个城市间的最短导弹飞行时间,并利用二分趋近法和匈牙利算法找出最优的导弹部署方案,以最小化国家A摧毁国家B所需的时间。

一个大陆上有K个城市,其中有N个城市属于国家A,M个城市属于国家B。给出导弹在任意两个城市间的飞行时间,问若国家A的每个城市都部署了一枚导弹,求国家A摧毁国家B最少需要多少时间。
第一届新手赛预选赛的最后一题,属于图论问题,综合了多种算法,貌似只有一个测试样例,时间要求并不苛刻。首先,用佛洛依德算法求出任意两个城市间最短的导弹飞行时间(导弹居然会转弯……),再用二分趋近的方法,对每一个可能的时间,用匈牙利算法判断二分图(国家A和国家B)的最大匹配是否是完全匹配,进而求出最小时间。
另:佛洛依德算法比较容易理解,关键在于寻求中间节点C使得从A到C再到B的时间比从A到B的时间少(当然C不一定存在)。C点依次选取所有的节点,核心思路是二二归一达到最简,方法简单易行但耗时较大。而匈牙利算法的关键在于寻求增广路径,以此来不断扩充(就是将增广路径上的每条边都取反,匹配数就多了一个)原来的匹配图,直到最大匹配,个中还涉及了深度优先检索的算法。

Run Time: 0.04sec

Run Memory: 348KB

Code length: 2077Bytes

SubmitTime: 2011-12-16 12:08:32

// Problem#: 1794
// Submission#: 1090043
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include <cstdio>  
#include <cstring>
using namespace std;

int K, N, M;
int time[ 101 ][ 101 ];
int A[ 101 ], B[ 101 ];
int attack[ 101 ], defend[ 101 ];
bool included[ 101 ];

bool find( int n, int min );
bool match( int min );

int main()
{
    int i, j, k;
    int bot, top, mid;

    while ( scanf( "%d", &K ) && K ) {
        for ( i = 1; i <= K; i++ ) {
            for ( j = 1; j <= K; j++ )
                scanf( "%d", &time[ i ][ j ] );
        }

        for ( k = 1; k <= K; k++ ) {
            for ( i = 1; i <= K; i++ ) {
                for ( j = 1; j <= K; j++ ) {
                    if ( time[ i ][ k ] + time[ k ][ j ] < time[ i ][ j ] )
                        time[ i ][ j ] = time[ i ][ k ] + time[ k ][ j ];
                }
            }
        }

        scanf( "%d", &N );
        for ( i = 1; i <= N; i++ )
            scanf( "%d", &A[ i ] );
        scanf( "%d", &M );
        for ( i = 1; i <= M; i++ )
            scanf( "%d", &B[ i ] );

        bot = 1;
        top = 100;
        while ( bot < top ) {
            mid = ( bot + top ) / 2;
            match( mid ) ? top = mid - 1: bot = mid + 1;
        }
        printf( "%d\n", match( top ) ? top: top + 1 );
    }

    return 0;

}


bool find( int n, int min ) {
    for ( int i = 1; i <= N; i++ ) {
        if ( time[ A[ i ] ][ n ] <= min && !included[ A[ i ] ] ) {
            included[ A[ i ] ] = true;
            if ( attack[ A[ i ] ] == 0 || find( attack[ A[ i ] ], min ) ) {
                defend[ n ] = A[ i ];
                attack[ A[ i ] ] = n;
                return true;
            }
        }
    }
    return false;
}

bool match( int min ) {
    memset( attack, 0, sizeof( attack ) );
    memset( defend, 0, sizeof( defend ) );
    for ( int i = 1; i <= M; i++ ) {
        if ( defend[ B[ i ] ] == 0 ) {
            memset( included, false, sizeof( included ) );
            if ( !find( B[ i ], min ) )
                return false;
        }
    }
    return true;
}                                 



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值