• 洛谷2474 [SCOI2008] 天平 差分约束->枚举


    题目描述

    你有n个砝码,均为1克,2克或者3克。你并不清楚每个砝码的重量,但你知道其中一些砝码重量的大小关系。你把其中两个砝码A 和B 放在天平的左边,需要另外选出两个砝码放在天平的右边。问:有多少种选法使得天平的左边重(c1)、一样重(c2)、右边重(c3)?(只有结果保证惟一的选法才统计在内)

    输入输出格式

    输入格式:

    第一行包含三个正整数n,A,B(1<=A,B<=N,A 和B 不相等)。砝码编号

    为1~N。以下n行包含重量关系矩阵,其中第i行第j个字符为加号“+”表示砝

    码i比砝码j重,减号“-”表示砝码i比砝码j 轻,等号“=”表示砝码i和砝码

    j一样重,问号“?”表示二者的关系未知。存在一种情况符合该矩阵。

    输出格式:

    仅一行,包含三个整数,即c1,c2和c3。

    输入输出样例

    输入样例#1: 
    6 2 5
    ?+????
    -?+???
    ?-????
    ????+?
    ???-?+
    ????-?
    输出样例#1: 
    1 4 1
    输入样例#2:
    14 8 4
    ?+???++?????++
    -??=?=???????=
    ??????????=???
    ?=??+?==??????
    ???-???-???-??
    -=????????????
    -??=???=?-+???
    ???=+?=???????
    ??????????????
    ??????+???????
    ??=???-????-??
    ????+?????+???
    -?????????????
    -=????????????
    输出样例#2:
    18 12 11

    说明

    4<=n<=50

    给出A 和 B 找出C和 D 求A+B>C+D  A+B=C+D  A+B<C-D 

    由 A+B>C+D   ->   A-C>D-B   ->   A-C的最小值>D-B的最大值    就能想到了差分约束

    于是我们要差分约束把每两个砝码的最大差值和最小差值算出来 之后暴力枚举即可

    之后细节见代码

    代码

    #include<bits/stdc++.h>
    using namespace std;
    int N,A,B,dx[55][55],dn[55][55],ans1,ans2,ans3;
    char s[55];
    int main()
    {
        scanf("%d%d%d",&N,&A,&B);
        for(int i=1;i<=N;i++){
            scanf("%s",s);
            for(int j=0;j<strlen(s);j++){                     //读字符矩阵建图
                if(s[j]=='='||i==j+1)dx[i][j+1]=0, dn[i][j+1]=0 ;      //相等 ->  相差0
                else if(s[j]=='+')     dx[i][j+1]=2, dn[i][j+1]=1 ;     //大于 ->  最多差1,最小差2  
                else if(s[j]=='-')     dx[i][j+1]=-1,dn[i][j+1]=-2;
                else if(s[j]=='?')     dx[i][j+1]=2, dn[i][j+1]=-2;       
            }
        }
        for(int k=1;k<=N;k++)                            //floyed求一下所有砝码的互相关系
            for(int i=1;i<=N;i++)
                if(i!=k)for(int j=1;j<=N;j++)
                    if(i!=k&&i!=j)
                        dx[i][j]=min(dx[i][j],dx[i][k]+dx[k][j]),
                        dn[i][j]=max(dn[i][j],dn[i][k]+dn[k][j]);
        for(int i=1;i<=N;i++)                            //然后暴力枚举统计答案
            if(i!=A&&i!=B)for(int j=1;j<i;j++)
                if(j!=A&&j!=B){
                    if(dn[A][i]>dx[j][B]||dn[B][i]>dx[j][A])ans1++;
                    if(dn[i][A]>dx[B][j]||dn[i][B]>dx[A][j])ans3++;
                    if((dn[A][i]==dx[A][i]&&dn[j][B]==dx[j][B]&&dn[A][i]==dn[j][B])||(dn[A][j]==dx[A][j]&&dn[i][B]==dx[i][B]&&dn[A][j]==dn[i][B]))ans2++;
                }
        printf("%d %d %d",ans1,ans2,ans3);
        return 0;                    
    }
  • 相关阅读:
    【[SDOI2014]旅行】
    【[USACO16OPEN]262144】
    【[SDOi2012]Longge的问题】
    【[POI2000]病毒】
    【不同子串个数】
    【工艺】
    Lambda使用深入解析
    Lambda表达式语法进一步巩固
    给之前绘制的图形菜单增加随触摸360度旋转效果
    给之前绘制的饼状图增加点击扩大突出效果
  • 原文地址:https://www.cnblogs.com/Elfish/p/7713857.html
Copyright © 2020-2023  润新知