bzoj 3504(神题,网络流)

3504: [Cqoi2014]危桥

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 1165   Solved: 590
[ Submit][ Status][ Discuss]

Description

Alice和Bob居住在一个由N座岛屿组成的国家,岛屿被编号为0到N-1。某些岛屿之间有桥相连,桥上的道路是双
向的,但一次只能供一人通行。其中一些桥由于年久失修成为危桥,最多只能通行两次。Alice希望在岛屿al和a2之间往返an次(从al到a2再从a2到al算一次往返)。同时,Bob希望在岛屿bl和b2之间往返bn次。这个过程中,所有危桥最多通行两次,其余的桥可以无限次通行。请问Alice和Bob能完成他们的愿望吗?

Input


本题有多组测试数据。
每组数据第一行包含7个空格隔开的整数,分别为N、al、a2、an、bl、b2、bn。
接下来是一个N行N列的对称矩阵,由大写字母组成。矩阵的i行j列描述编号i一1和j-l的岛屿间的连接情况,若为“O”则表示有危桥相连:为“N”表示有普通的桥相连:为“X”表示没有桥相连。
|

Output

对于每组测试数据输出一行,如果他们都能完成愿望输出“Yes”,否则输出“No”。


Sample Input

4 0 1 1 2 3 1
XOXX
OXOX
XOXO
XXOX
4 0 2 1 1 3 2
XNXO
NXOX
XOXO
OXOX

Sample Output

Yes
No
数据范围
4<=N<50
O<=a1, a2, b1, b2<=N-1

1 <=an. b<=50


解题思路:

神题。。。 网上证明好像有问题。。

就是先建图,跑最大流,看ans是否是2*an+2*bn。 

满足的话,将b1,b2交换再做,再判断,如果还满足就满足。


以后遇到这种题的话,实在不会证,就看看是否是满足对称性的,再考虑交换来做。


#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define inf 0x7fffffff
#define ll long long
#define T 51
using namespace std ;
bool flag ;
int n , a1 , a2 , an , b1 , b2 , bn ;
int cnt , ans ;
int h [ 55 ] , q [ 55 ] ;
int mp [ 55 ] [ 55 ] ;
struct data { int to , next , v ; } e [ 100005 ] ; int head [ 55 ] , cur [ 55 ] ;
void ins ( int u , int v , int w )
{ e [ ++ cnt ] . to = v ; e [ cnt ] . next = head [ u ] ; head [ u ] = cnt ; e [ cnt ] . v = w ; }
void insert ( int u , int v , int w )
{ ins ( u , v , w ) ; ins ( v , u , 0 ) ; }
void build ( )
{
memset ( head , 0 , sizeof ( head ) ) ; cnt = 1 ;
for ( int i = 1 ; i <= n ; i ++ )
     for ( int j = 1 ; j <= n ; j ++ )
         if ( mp [ i ] [ j ] == 1 ) insert ( i , j , 2 ) ;
         else if ( mp [ i ] [ j ] == 2 ) insert ( i , j , inf ) ;
}
bool bfs ( )
{
     int t = 0 , w = 1 ;
     for ( int i = 0 ; i <= T ; i ++ ) h [ i ] = - 1 ;
     q [ 0 ] = 0 ; h [ 0 ] = 0 ;
     while ( t != w )
     {
         int now = q [ t ] ; t ++ ;
         for ( int i = head [ now ] ; i ; i = e [ i ] . next )
             if ( e [ i ] . v && h [ e [ i ] . to ] == - 1 )
             {
                 h [ e [ i ] . to ] = h [ now ] + 1 ;
                 q [ w ++ ] = e [ i ] . to ;
             }
     }
     if ( h [ T ] == - 1 ) return 0 ;
     return 1 ;
}
int dfs ( int x , int f )
{
     if ( x == T ) return f ;
     int w , used = 0 ;
     for ( int i = cur [ x ] ; i ; i = e [ i ] . next )
     {
         if ( e [ i ] . v && h [ e [ i ] . to ] == h [ x ] + 1 )
         {
             w = f - used ;
             w = dfs ( e [ i ] . to , min ( e [ i ] . v , w ) ) ;
             e [ i ] . v -= w ;
             if ( e [ i ] . v ) cur [ x ] = i ;
             e [ i ^ 1 ] . v += w ;
             used += w ; if ( used == f ) return f ;
         }
     }
     if ( ! used ) h [ x ] = - 1 ;
     return used ;
}
void dinic ( )
{ while ( bfs ( ) ) { for ( int i = 0 ; i <= T ; i ++ ) cur [ i ] = head [ i ] ; ans += dfs ( 0 , inf ) ; } }
int main ( )
{
while ( scanf ( "%d%d%d%d%d%d%d" , &n , &a1 , &a2 , &an , &b1 , &b2 , &bn ) != EOF )
{
memset ( mp , 0 , sizeof ( mp ) ) ; flag = 0 ;
a1 ++ ; a2 ++ ; b1 ++ ; b2 ++ ;
for ( int i = 1 ; i <= n ; i ++ )
{
char ch [ 55 ] ;
scanf ( "%s" , ch ) ;
for ( int j = 1 ; j <= n ; j ++ )
     if ( ch [ j - 1 ] == 'O' ) mp [ i ] [ j ] = 1 ;
     else if ( ch [ j - 1 ] == 'N' ) mp [ i ] [ j ] = 2 ;
}
build ( ) ;
insert ( 0 , a1 , an * 2 ) ; insert ( a2 , T , an * 2 ) ;
insert ( 0 , b1 , bn * 2 ) ; insert ( b2 , T , bn * 2 ) ;
ans = 0 ;
dinic ( ) ;
if ( ans < 2 * ( an + bn ) ) flag = 1 ;
if ( ! flag )
{
     build ( ) ;
     insert ( 0 , a1 , an * 2 ) ; insert ( a2 , T , an * 2 ) ;
     insert ( 0 , b2 , bn * 2 ) ; insert ( b1 , T , bn * 2 ) ;
     ans = 0 ;
     dinic ( ) ;
     if ( ans < 2 * ( an + bn ) ) flag = 1 ;
}
if ( flag ) printf ( "No\n" ) ;
else printf ( "Yes\n" ) ;
}
return 0 ;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值