【FJOI2018】 所罗门王的宝藏

所罗门王的宝藏

题意

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

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

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

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

Solution

一个i行j列格子上的数为w,就意味着i行转动的次数加上j列的次数为w次(次数可以为负数)

然后这样连个边,形成一个二分图,假设初始点是转了0次(也就是这一行转0次),那这样二分图环里的行和列的次数都是固定的。

然后check一下二分图里面的每个环是不是都符合要求即可,如果有冲突就不合法

code:

#include<bits/stdc++.h>
using namespace std;
struct qwq{
    int v;
    int w;
    int nxt;
}edge[200010];
int cnt=-1;
int head[200010];
void add(int u,int v,int w){
    edge[++cnt].nxt=head[u];
    edge[cnt].v=v;
    edge[cnt].w=w;
    head[u]=cnt;
}
int www[200010];
bool vis[200010];
bool flag;
void dfs(int u,int fa){
    vis[u]=true;
    if(flag)return;
    for(int i=head[u];~i;i=edge[i].nxt){
        int v=edge[i].v,w=edge[i].w;
        if(v==fa)continue;
        if(!vis[v]){
            www[v]=w-www[u];
            dfs(v,u);
        }
        else if(www[u]+www[v]!=w){
            flag=true;
            return;
        }
    }
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        memset(head,-1,sizeof(head));
        memset(www,0,sizeof(www));
        memset(vis,0,sizeof(vis));
        cnt=-1;
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=k;++i){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add(u,v+n,w);
            add(v+n,u,w);
        }
        flag=false;
        for(int i=1;i<=n;++i){
            if(!vis[i]){
                dfs(i,-1);
            }
        }
        puts((flag?"No":"Yes"));
    }
} 
posted @ 2019-10-30 22:10  FakeDragon  阅读(366)  评论(0编辑  收藏  举报