P2474 [SCOI2008]天平 差分约束

本文解析了一种基于三种砝码质量的算法问题,通过Floyd算法计算各点间差值范围,暴力枚举解,并详细阐述了如何判断不同质量关系的条件。涉及算法包括Floyd算法和暴力枚举。

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

神题,因为砝码的质量只有三种,所以,对于每一种关系,都有一个上下界,那么我们可以通过一个floyd来跑出各点之间的差值范围,然后暴力枚举出解
在爆枚过程中怎么判断是哪种情况呢
摘一下chen_zhe大佬的
若要满足A+B&lt;C+DA+B&lt;C+DA+B<C+D,那么只要满足A−C&lt;D−BA−C&lt;D−BAC<DB或者A−D&lt;C−BA−D&lt;C−BAD<CB就可以了

如果A−C&lt;D−BA−C&lt;D−BAC<DB一定成立,那么max⁡(A−C)&lt;min⁡(D−B)\max(A-C)&lt;\min(D-B)max(AC)<min(DB),A−D<C−B同理

若要满足A+B=C+DA+B=C+DA+B=C+D,那么只要满足A−C=D−BA−C=D−BAC=DB或者A−D=C−BA−D=C−BAD=CB就可以了

如果A−C=D−BA−C=D−BAC=DB一定成立,那么min⁡(A−c)=max⁡(A−c)=min⁡(D−B)=max⁡(D−B)\min(A-c)=\max(A-c)=\min(D-B)=\max(D-B)min(Ac)=max(Ac)=min(DB)=max(DB)

A−D=C−BA−D=C−BAD=CB同理,A+B&gt;C+DA+B&gt;C+DA+B>C+D同理

			if(mn[s1][i]>mx[j][B] || mn[B][i]>mx[j][A])
                c1++;      //A+B>i+j <=> i-A<B-j
            if(mn[i][A]>mx[B][j] || mn[i][B]>mx[A][j])
                c3++;      //i+j>A+B <=> i-A>B-j
            if((mn[A][i]==mx[A][i] && mn[j][B]==mx[j][B] && mn[A][i]==mn[j][B]) || 
            (mn[A][j]==mx[A][j] && mn[i][B]==mx[i][B] && mn[A][j]==mn[i][B]))
                c2++;     //由上可得

完整的

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

const int maxn = 53;
int mx[maxn][maxn],mn[maxn][maxn];
int n,A,B,c1,c2,c3;
int main()
{
    scanf("%d%d%d",&n,&A,&B);
    for(int i=1;i<=n;++i)
    {
        char ch[maxn];
        scanf("%s",ch+1);
        for(int j=1;j<=n;j++)
        {
            if(ch[j]=='?')
            {
                mx[i][j]=2;
                mn[i][j]=-2;
            }
            else if(ch[j]=='+')
            {
                mx[i][j]=2;
                mn[i][j]=1;
            }
            else if(ch[j]=='-')
            {
                mx[i][j]=-1;
                mn[i][j]=-2;
            }
            else
            {
                mx[i][j]=mn[i][j]=0;
            }
        }
    }
    for(int k=1;k<=n;k++)
        for(int j=1;j<=n;j++)
            for(int i=1;i<=n;i++)
                if(i!=j&&i!=k&&k!=j)
                {
                    mx[i][j]=min(mx[i][k]+mx[k][j],mx[i][j]);
                    mn[i][j]=max(mn[i][k]+mn[k][j],mn[i][j]);
                }
    for(int i=1;i<=n;i++)
    {
        if(i==A||i==B)continue;
        for(int j=1;j<=n;j++)
        {
            if(i==j)continue;
            if(j==A||j==B)continue;
            if(mn[A][i]>mx[j][B]||mn[B][i]>mx[j][A])c1++;
            if((mn[A][i]==mx[A][i]&&mn[j][B]==mx[j][B]&&mn[A][i]==mn[j][B])||(mn[A][j]==mx[A][j]&&mn[i][B]==mx[i][B]&&mn[A][j]==mn[i][B]))c2++;
            if(mn[i][A]>mx[B][j]||mn[i][B]>mx[A][j])c3++;
        }
    }
    printf("%d %d %d",c1/2,c2/2,c3/2);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值