bzoj千题计划137:bzoj [CQOI2014]危桥

http://www.lydsy.com/JudgeOnline/problem.php?id=3504

往返n遍,即单向2*n遍

危桥流量为2,普通桥流量为inf

原图跑一遍最大流

交换b1,b2再跑一遍最大流

如果两次的结果都等于(an+bn)*2

则可以

证明参见http://www.cnblogs.com/chenyushuo/p/5139556.html

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

#define N 100
#define M 3000

const int inf=1e9;

int n,a1,a2,an,b1,b2,bn;

char s[51][51];

int tot;
int front[N],nxt[M<<1],to[M<<1],val[M<<1],from[M<<1];
int lev[N],num[N];
int path[N];
int cur[N];

int src,decc;

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c))  c=getchar();
    while(isdigit(c)) { x=x*10+c-‘0‘; c=getchar();  }
}

void add(int u,int v,int w)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; from[tot]=u; val[tot]=w;
    to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; from[tot]=v; val[tot]=0;
}

void build()
{
    tot=1;
    memset(front,0,sizeof(front));
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)
        {
            if(s[i][j]==‘O‘) add(i,j,2);
            else if(s[i][j]==‘N‘) add(i,j,inf);
        }
    src=0; decc=n+1;
    add(src,a1,an<<1);
    add(a2,decc,an<<1);
    add(src,b1,bn<<1);
    add(b2,decc,bn<<1);
}

bool bfs()
{
    queue<int>q;
    for(int i=src;i<=decc;++i) lev[i]=decc+1;
    q.push(decc);
    lev[decc]=0;
    int now,t;
    while(!q.empty())
    {
        now=q.front();
        q.pop();
        for(int i=front[now];i;i=nxt[i])
        {
            t=to[i];
            if(lev[t]==decc+1 && val[i^1])
            {
                lev[t]=lev[now]+1;
                q.push(t);
            }
        }
    }
    return lev[src]!=decc+1;
}

int augment()
{
    int now=decc,flow=inf;
    int i;
    while(now!=src)
    {
        i=path[now];
        flow=min(flow,val[i]);
        now=from[i];
    }
    now=decc;
    while(now!=src)
    {
        i=path[now];
        val[i]-=flow;
        val[i^1]+=flow;
        now=from[i];
    }
    return flow;
}

int isap()
{
    int flow=0;
    if(!bfs()) return 0;
    memset(num,0,sizeof(num));
    for(int i=src;i<=decc;++i) num[lev[i]]++,cur[i]=front[i];
    int now=src,t;
    while(lev[src]<=decc)
    {
        if(now==decc)
        {
            flow+=augment();
            now=src;
        }
        bool advanced=false;
        for(int i=cur[now];i;i=nxt[i])
        {
            t=to[i];
            if(lev[t]==lev[now]-1 && val[i])
            {
                advanced=true;
                path[t]=i;
                cur[now]=i;
                now=t;
                break;
            }
        }
        if(!advanced)
        {
            int mi=decc;
            for(int i=front[now];i;i=nxt[i])
                if(val[i]) mi=min(mi,lev[to[i]]);
            if(!--num[lev[now]]) break;
            num[lev[now]=mi+1]++;
            cur[now]=front[now];
            if(now!=src) now=from[path[now]];
        }
    }
    return flow;
}

int main()
{
    int A,B;
    while(scanf("%d",&n)!=EOF)
    {
        read(a1); read(a2); read(an);
        a1++; a2++;
        read(b1); read(b2); read(bn);
        b1++; b2++;
        for(int i=1;i<=n;++i) scanf("%s",s[i]+1);
        build();
        A=isap();
        if(A!=(an+bn)*2)
        {
            puts("No");
            continue;
        }
        swap(b1,b2);
        build();
        B=isap();
        puts(A==B ? "Yes" : "No");
    }
}

3504: [Cqoi2014]危桥

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1739  Solved: 868
[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

时间: 2024-10-10 22:26:30

bzoj千题计划137:bzoj [CQOI2014]危桥的相关文章

bzoj千题计划185:bzoj1260: [CQOI2007]涂色paint

http://www.lydsy.com/JudgeOnline/problem.php?id=1260 区间DP模型 dp[l][r] 表示涂完区间[l,r]所需的最少次数 从小到大们枚举区间[l,r] 如果col[l]==col[r] dp[l][r]=min(dp[l+1][r],dp[l][r-1],dp[l+1][r-1]+1) 否则 dp[l][r]=min(dp[l][k]+dp[k+1][r]) 我还是辣鸡啊~~~~(>_<)~~~~,这种题都不能秒 #include<c

bzoj千题计划292:bzoj2244: [SDOI2011]拦截导弹

http://www.lydsy.com/JudgeOnline/problem.php?id=2244 每枚导弹成功拦截的概率 = 包含它的最长上升子序列个数/最长上升子序列总个数 pre_len [i] 表示以i结尾的最长不下降子序列的长度 pre_sum[i] 表示对应长度下的方案数 suf_len[i] 表示以i开头的最长不下降子序列长度 suf_sum[i] 表示对应长度下的方案数 若已有了这4个数组 设最长上升子序列长度=mx 那么 如果pre_len[i]+suf_len[i] -

bzoj千题计划304:bzoj3676: [Apio2014]回文串

https://www.lydsy.com/JudgeOnline/problem.php?id=3676 回文自动机模板题 4年前的APIO如今竟沦为模板,,,╮(╯▽╰)╭,唉 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 300001 char ss[N]; int s[N]; int tot=1,last; int fail[N],len

bzoj千题计划106:bzoj1014 [JSOI2008]火星人prefix

http://www.lydsy.com/JudgeOnline/problem.php?id=1014 两个后缀的最长公共前缀:二分+hash 带修改带插入:splay维护 #include<cstdio> #include<cstring> #include<iostream> #define L 100001 typedef unsigned long long ULL; using namespace std; char s[L+4]; int tot,root

bzoj千题计划108:bzoj1018: [SHOI2008]堵塞的交通traffic

http://www.lydsy.com/JudgeOnline/problem.php?id=1018 关键点在于只有两行 所以一个2*m矩形连通情况只有6种 编号即对应代码中的a数组 线段树维护 用b数组表示 节点第0/1行的最右一列是否连接了右边 来 辅助 节点的合并 查询 对两个点位于矩形的位置分4种情况讨论 两点是否联通,要考虑四种情况 (以两个位置是矩形左上角和右上角为例) 1.直接联通,线段树的节点包含了这种情况,直接判断 2. 3. 4. 后三种情况需要再查询[1,l]和[r,n

bzoj千题计划109:bzoj1019: [SHOI2008]汉诺塔

http://www.lydsy.com/JudgeOnline/problem.php?id=1019 题目中问步骤数,没说最少 可以大胆猜测移动方案唯一 (真的是唯一但不会证) 设f[i][j] 表示 从i号柱子 上把j个盘子移到 g[i][j] 柱子上的步数 初始化:f[0][1]=1,g[0][1] 根据优先级决定 设三根柱子分别为0,1,2 对于每一个f[x][i], 把前i-1个移走,把第i个移走,把前i-1个移回 令y=g[x][i-1],则k=0+1+2-x-y 我们希望 把i-

bzoj千题计划111:bzoj1021: [SHOI2008]Debt 循环的债务

http://www.lydsy.com/JudgeOnline/problem.php?id=1021 如果A收到了B的1张10元,那么A绝对不会把这张10元再给C 因为这样不如B直接给C优 由此可以推出 若A欠B20元,B欠C 30元, 那么A还C20元,B还C10元最优 所以一共只有 A->BC   B->AC  C->AB AB->C  BC->A  AC->B 这6种转移情况 根据输入,我们可以知道三人最终手中有多少钱ea.eb.ec,一共有多少钱sum 设f

bzoj千题计划112:bzoj1022: [SHOI2008]小约翰的游戏John

http://www.lydsy.com/JudgeOnline/problem.php?id=1022 http://www.cnblogs.com/TheRoadToTheGold/p/6744825.html #include<cstdio> #include<iostream> using namespace std; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar();

bzoj千题计划113:bzoj1023: [SHOI2008]cactus仙人掌图

http://www.lydsy.com/JudgeOnline/problem.php?id=1023 dp[x] 表示以x为端点的最长链 子节点与x不在同一个环上,那就是两条最长半链长度 子节点与x在同一个环上,环形DP,单调队列优化 对于每一个环,深度最小的那个点 有可能会更新 上层节点, 所以 每一个环DP完之后,更新 dp[深度最小的点] #include<cstdio> #include<iostream> #include<algorithm> using