zoukankan      html  css  js  c++  java
  • bzoj1077: [SCOI2008]天平 差分约束

    Description

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

    Input

      第一行包含三个正整数n,A,B(1<=A,B<=N,A和B不相等)。砝码编号为1~N。以下n行包含重量关系矩阵,
    其中第i行第j个字符为加号“+”表示砝码i比砝码j重,减号“-”表示砝码i比砝码j轻,等号“=”表示砝码i和砝
    码j一样重,问号“?”表示二者的关系未知。存在一种情况符合该矩阵

    Output

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

    题解

    由于题目要求求(A+B)(i+j)的关系,我们考虑移位,考虑(A-i)(j-B)的关系,记(mx[i][j])(mn[i][j])(i-j)的最大值和最小值。然后根据题目描述确定(i,j)关系,接着(Floyd)跑最短路,基本的差分约束操作,然后找到一定符合要求的更新答案。详细的看代码~

    代码

    #include<iostream> 
    #include<cstdio> 
    #include<cstring> 
    #include<algorithm> 
    using namespace std;
    int n,A,B;
    char s[60];
    int mx[60][60],mn[60][60];
    int c1,c2,c3;
    int main(){
        ios::sync_with_stdio(false);
        cin>>n>>A>>B;
        for(int i=1;i<=n;i++){
        cin>>(s+1);
            for(int j=1;j<=n;j++){
                if(s[j]=='='||i==j) mx[i][j]=mn[i][j]=0;
                else if(s[j]=='+') mx[i][j]=2,mn[i][j]=1;//若i>j则i-j<=2  i-j>=1
                else if(s[j]=='-') mx[i][j]=-1,mn[i][j]=-2;//若i<j 则i-j<=1 i-j>=-2
                else mx[i][j]=2,mn[i][j]=-2; 
            }
        }
        for(int k=1;k<=n;k++) for(int i=1;i<=n;i++){ //Floyd求最短路
            if(i==k)continue;
            for(int j=1;j<=n;j++){
                if(i==j||i==k)continue;
            	mx[i][j]=min(mx[i][j],mx[i][k]+mx[k][j]);
            	mn[i][j]=max(mn[i][j],mn[i][k]+mn[k][j]);
        	}
        }
        for(int i=1;i<=n;i++){
            if(i==A||i==B)continue;
            for(int j=i+1;j<=n;j++){
                if(j==A||j==B||j==i)continue;
                if(mn[A][i]>mx[j][B]||mn[B][i]>mx[j][A])c1++; //若A+B>i+j 则A-i的最小值一定大于j-B的最大值
                if(mn[i][A]>mx[B][j]||mn[i][B]>mx[A][j])c3++;//若A+B<i+j 则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++;//必须全部相等
            }
        }
        cout<<c1<<" "<<c2<<" "<<c3<<endl;
        return 0;
    }
    
  • 相关阅读:
    [树形dp] Jzoj P5814 树
    [快速幂][数学][dp] Jzoj P5813 计算
    [差分] Jzoj P5812 区间
    [贪心][模拟] Jzoj P5811 简单的填数
    如何用c++发出音乐
    网络流初步详解
    【纪中模拟2019.08.01】【JZOJ2644】数列
    【纪中模拟2019.08.02】【JZOJ1308】取数游戏
    2019.08纪中 XC谈OI学习方法论
    C++STL容器
  • 原文地址:https://www.cnblogs.com/Nan-Cheng/p/9752171.html
Copyright © 2011-2022 走看看