中国石油大学OJ 第五场个人训练赛 所罗门王的宝藏

问题 C: 所罗门王的宝藏

时间限制: 1 Sec  内存限制: 128 MB
提交: 133  解决: 50
[提交] [状态] [讨论版] [命题人:admin]

题目描述

据古代传说记载,所罗门王既是智慧的代表,又是财富的象征。他建立了强大而富有的国家,聚集了大批的黄金象牙和钻石,并把这些价值连城的珍宝藏在一个神秘的地方,这就是世人瞩目的“所罗门王的宝藏”。多少个世纪以来,人们一直在寻找这批早已失落的古代文明宝藏,寻找盛产黄金和钻石的宝地。曾经追寻所罗门王宝藏的冒险者们都一去不回,至今没人解开这个谜题。亨利男爵在一次幸运的旅途中意外地得到了三百年前一位葡萄牙贵族留下的写在羊皮卷上的所罗门王的藏宝图和一本寻宝秘籍。在这张藏宝图的诱惑下,亨利男爵邀请约翰上校和勇敢的猎象人夸特曼开始了寻找埋葬在黑暗地底的所罗门王宝藏的艰险历程。他们横穿渺无边际的沙漠和浓荫蔽日的原始森林,越过汹涌澎湃的激流险滩,翻越高耸入云的峻岭雪山,饱尝沙漠的酷热和冰雪严寒,在藏宝图的指引下来到非洲一个原始的神秘国度库库安纳。这里有残酷的人殉制度,有一个拥有一千个妻室的独眼暴君特瓦拉,有像兀鹫一般丑恶诡诈老而不死的女巫加古尔,还有美丽聪慧的绝代佳人弗拉塔。在这片陌生而又险象环生的土地上三位寻宝英雄历尽艰辛,终于在绝代佳人弗拉塔的帮助下在海底深处找到了珍藏这批价值连城宝藏的巨大的藏宝洞。然而在女巫加古尔的精心策划下,一场灭顶之灾正在悄悄逼近。

藏宝洞的洞门十分坚固且洞门紧闭,如果不知道开启洞门的秘密是无法打开藏宝洞的洞门。在藏宝洞的洞门一侧有一个奇怪的矩形密码阵列。根据寻宝秘籍的记载,在密码阵列每行的左侧和每列的顶端都有一颗红宝石按钮。每个按钮都可以向左或向右转动。每向左转动一次按钮,相应的行或列中数字都增 1。每向右转动一次按钮,相应的行或列中数字都减 1。在矩形密码阵列的若干特定位置镶嵌着绿宝石。只有当所有绿宝石位置的数字与藏宝图记载的密码完全相同,紧闭的洞门就会自动缓缓打开。女巫加古尔早已得知开门的秘密。为了阻止寻宝者打开洞门,女巫加古尔为开门的密码阵列设置了全0的初始状态。试图打开洞门的寻宝者如果不能迅速转动按钮使所有绿宝石位置的数字与藏宝图记载的密码完全相同,就会自动启动藏宝洞玄妙的暗器机关,使寻宝者遭到灭顶攻击而死于非命。

您能帮助三位寻宝英雄顺利打开藏宝洞的洞门吗?

编程任务:对于给定的密码阵列,找到获得正确密码的红宝石按钮的转动序列。

输入

输入的第一行中有一个正整数T(T≤5)表示有T组数据。每组数据的第一行有3个正整数n,m和k,表示洞门密码阵列共有n行和m列,0<n,m,k≤1000。各行从上到下依次编号为1,2,…,n;各列从左到右依次编号为1,2,…,m。接下来的k行中每行有三个整数x,y,c,分别表示第k个绿宝石在密码阵列中的位置和密码,x为行号y为列号,c为该位置处的密码。

输出

对于每组数据,用一行输出 Yes 或者 No。输出 Yes 表示存在获得正确密码的红宝石按钮的转动序列。输出 No 则表示无法找到获得正确密码的红宝石按钮的转动序列。

样例输入

2
2 2 4
1 1 0
1 2 0
2 1 2
2 2 2
2 2 4
1 1 0
1 2 0
2 1 2
2 2 1

样例输出

Yes
No

提示

对于100%的数据,1≤n,m,k≤1000,k≤n×m,∣c∣≤1,000,000。

题解:刚看到这道题的时候以为是一道高斯消元,因为感觉完全可以列成多个方程的样子,最后判断方程组是否有解即可,但是因为不会高斯消元就放弃了,赛后看题解才发现原来可以暴力水过,复杂度O(k*k),用数组row[i]代表第i行的按钮对第i行的影响,数组col[i]代表第i列的按钮对第i列的影响,于是在同一行或者同一列的密码之间就可以构成一种联系,即mp[row[i]][row[j]]=v[i]-v[j];一旦找到与之前相矛盾的就可以直接判定无解了。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
int mp1[1005][1005],mp2[1005][1005],vis1[1005][1005],vis2[1005][1005],row[1005],col[1005],n,m,k,v[1005];
 
void input()
{
    memset(mp1,0,sizeof(mp1));
    memset(mp2,0,sizeof(mp2));
    memset(vis1,0,sizeof(vis1));
    memset(vis2,0,sizeof(vis2));
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=k;i++)
        scanf("%d%d%d",&row[i],&col[i],&v[i]);
}
 
int cha(int i,int j,int f)
{
    if(f)
    {
        if(row[i]>row[j]) swap(i,j);
        return v[i]-v[j];
    }
    else
    {
        if(col[i]>col[j]) swap(i,j);
        return v[i]-v[j];
    }
}
 
int solve()
{
    for(int i=1;i<=k;i++)
        for(int j=i+1;j<=k;j++)
            if(row[i]==row[j] && col[i]==col[j] && v[i]!=v[j]) return 0;
            else if(row[i]==row[j])
            {
                if(vis1[col[i]][col[j]] && mp1[col[i]][col[j]]!=cha(i,j,0)) return 0;
                mp1[col[i]][col[j]]=cha(i,j,0);
                vis1[col[i]][col[j]]=1;
            }
            else if(col[i]==col[j])
            {
                if(vis2[row[i]][row[j]] && mp2[row[i]][row[j]]!=cha(i,j,1)) return 0;
                mp2[row[i]][row[j]]=cha(i,j,1);
                vis2[row[i]][row[j]]=1;
            }
    for(int i=1;i<=n;i++) if(mp1[i][i]) return 0;
    for(int i=1;i<=m;i++) if(mp2[i][i]) return 0;
    return 1;
}
 
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        input();
        if(solve())
            printf("Yes\n");
        else
            printf("No\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sudu6666/article/details/81280889
今日推荐