【题目大意】

有多个珠子,给出部分珠子之间的相对上下位置和间距,问你这些珠子在满足给出的条件下,是否能把珠子排列在一条竖直直线上,如果能,求出每个珠子距离最高的珠子的距离,珠子的位置可重叠。

【分析】

可以根据珠子的位置关系建立一张有向图,A->B 为A比B高,权值为之间的距离。可以发现必须满足下列三种情况:

1、图有连通;无法比较出不同连通分支的上下关系。
               2、有向图没有环;根据位置的传递关系,不可能自己比自己低。
               3、如果从A到B有多条路径,路径的长度都应该一样;要不然B的位置关系就会有二义性。

我本来的想法是按顺序验证上面三条规则,把有向图转为无向图判联通,用拓扑排序判环,用DFS来判路径长度,想想太复杂了。后来想想其实没必要那么复杂。对于每条有向边,添加一条负权反向边,任意选定一个点,假设它是最高点,离最高点的距离是0,用DFS搜索可连向的点,如果新点未访问,则新点的距离就是当前点的距离加上边的权值,如果新点被访问过,这需要验证当前点的距离加上边权是否与新点原来的权值相等,如果不相等,则说明有冲突。如果DFS结束还有点没被访问,则说明图不连通。如果发现有点的距离为负数,则说明那个点比搜索开始的点的距离更高。

DFS的代码很简单:

 1 #include <stdio.h>
 2 #include <string.h>
 3 struct node
 4 {
 5     int x,y,c,next;
 6     void mset(int a,int b,int z,int nn)
 7     {
 8         x=a;
 9         y=b;c=z;
10         next=nn;
11     }
12 }ev[5000];
13 int ej,n,p;
14 int map[502];
15 int vv[502][502];
16 int num[502];
17 int dis[502];
18 bool ans;
19 int mmin;
20 int min(int a,int b){return a<b?a:b;}
21 void insert(int x,int y,int v)
22 {
23     int tem=map[x];
24     ev[ej++].mset(x,y,v,tem);
25     map[x]=ej-1;
26     vv[x][y]=v;
27     vv[y][x]=-v;
28 }
29 void dfs(int x)
30 {
31     if (num[x]) return;
32     num[x]=1;
33     int p=map[x];
34     while (p!=-1 && ans)
35     {
36        node tt=ev[p];
37        int t2=dis[x]+tt.c;
38        if (dis[tt.y]!=-1 && dis[tt.y]!=t2)
39         {
40             ans=false;
41             return;
42         }
43        dis[tt.y]=t2;
44        dfs(tt.y);
45        p=tt.next;
46     }
47 }
48 int main()
49 {
50     ej=0;mmin=0;
51     ans=true;
52     //freopen("in.txt","r",stdin);
53     memset(map,-1,sizeof map);
54     memset(num,0,sizeof num);
55     memset(dis,-1,sizeof dis);
56     scanf("%d%d",&n,&p);
57     for (int i=0;i<p;++i)
58     {
59         int a,b,c;
60         scanf("%d%d%d",&a,&b,&c);
61         insert(a,b,c);
62         insert(b,a,-c);
63         num[b]=1;
64     }
65     int p=0;
66     for (int i=1;i<=n;++i)
67       if (num[i]==0) {p=i;break;}
68     memset(num,0,sizeof num);
69     if (p==0)
70     {
71         printf("-1\n");
72         return 0;
73     }
74     //printf("%d\n",p);
75     dis[p]=0;
76     dfs(p);
77     if (!ans)
78     {
79         printf("-1\n");
80     } else
81     {
82         for (int i=1;i<=n;++i) mmin=min(mmin,dis[i]);
83          for (int i=1;i<=n;++i) printf("%d\n",dis[i]-mmin);
84     }
85
86 }

View Code

另外还可以使用并查集的方法,A是B的双亲就表示A的位置比B的高,对于每个节点保存当前到双亲节点的距离(为正值),这样在并查集的树中,根节点与一个孩子的孩子的孩子.....的孩子的距离就可以在路径压缩的过程中计算出来:

int find(int x)
{if (mset[x]==-1) return x;int t=mset[x];d[x]+=d[t];  //递推出与根节点的距离return mset[x]=find(t);
}

对于两个不同集合的合并,由于在找集合的过程中使用了find函数,所以相关节点一定直接和集合树的根节点连接。设现在要连接的节点是a、b,它们的根节点分别是roota和rootb, a与b的距离为c, a在b的上面。集合的合并是集合根节点之间的连接,所以需要计算出根节点之间的距离P,b到roota的距离应为d[a]+c, b到rootb的距离为d[b] ,假设rootb成为roota的孩子,着P+d[b]=d[a]+c => P=d[a]+c-d[b].若P为负,则roota应成为roota的孩子,距离为P的绝对值。

 1 #include <stdio.h>
 2 #include <string.h>
 3 int mset[500];
 4 int d[500],n,p;
 5 int find(int x)
 6 {
 7     if (mset[x]==-1) return x;
 8     int t=mset[x];
 9     d[x]+=d[t];
10     return mset[x]=find(t);
11 }
12
13 int main()
14 {
15     while (~scanf("%d%d",&n,&p))
16     {
17         memset(mset,-1,sizeof mset);
18         memset(d,0,sizeof d);
19         bool ans=true;
20         for (int i=0;i<p && ans;++i)
21         {
22             int a,b,c;
23             scanf("%d%d%d",&a,&b,&c);
24             int xx=find(a);
25             int yy=find(b);
26             int p=d[a]+c-d[b];
27             if (xx!=yy)
28             {
29                 if (p>=0)
30                 {
31                     mset[yy]=xx;d[yy]=p;
32                 } else
33                 {
34                     mset[xx]=yy;d[xx]=-p;
35                 }
36             } else
37             {
38                 if (d[a]+c!=d[b]) ans=false;
39             }
40         }
41         for (int i=1;i<=n;++i) find(i);
42         if (ans)
43            for (int i=1;i<=n;++i) printf("%d\n",d[i]);
44         else printf("-1\n");
45     }
46 }

View Code

这里能用并查集是利用了孩子和双亲关系的可传递性。

转载于:https://www.cnblogs.com/wuminye/p/3182467.html

VIJOS P1540 月亮之眼相关推荐

  1. VIJOS 1540 月亮之眼

    描述 吉儿是一家古董店的老板娘,由于她经营有道,小店开得红红火火.昨天,吉儿无意之中得到了散落民间几百年的珍宝-月亮之眼.吉儿深知"月亮之眼"价值连城:它是由许多珍珠相连而成的,工 ...

  2. 《算法艺术与信息学竞赛》题目-提交方式对照表 [转]

    id   title how2submit source page 1   盒子里的气球     8 2   图书馆 ural1188   9 3   钓鱼 uva757 pas 13 4   照亮的 ...

  3. java月亮升起与落下动画设计_Java版1.0.0/开发版本

    本页面列出了Java版1.0.0的开发版本. Beta 1.9-pre1 Beta 1.9 Prerelease是Java版1.0.0的首个预发布版. 它被称为"丢失的更新", 新 ...

  4. vijos 1006 晴天小猪历险记之Hill——数字三角形的终极变化

    题目链接:https://vijos.org/p/1006 数字三角形原题看这里:http://www.cnblogs.com/huashanqingzhu/p/7326837.html 背景 在很久 ...

  5. vijos 1476 旅游规划题解

    题目链接:https://vijos.org/p/1476 解:因为这一定是一棵树,所以我们多画几次图,就会发现所有的最长路径中心点都一样,且中心点把这条最长路径分成两段等长的路. 那么做法就很简单啦 ...

  6. 这是一张很有趣的图片, 通常女性会先看到月亮, 男性会先看到人脸. 如果相反, 表示你体内的异性荷尔蒙偏高哦!...

    这是一张很有趣的图片, 通常女性会先看到月亮, 男性会先看到人脸. 如果相反, 表示你体内的异性荷尔蒙偏高哦! 四不像...

  7. R画月亮阴晴圆缺:corrplot绘图相关系数矩阵

    今天是十五元宵节,即是和家人团聚的机会,也是赏月的好日子. 但作为科研汪的我,在狗年应更加努力,争取在狗年旺旺,从加班狗中脱颖而出. 分享一个相关分析可视化实战,祝大家元宵节快乐! 先给大家送一个我画 ...

  8. kali linux解密栅栏密码,犯罪大师上帝之眼答案最新

    犯罪大师上帝之眼答案最新为玩家带来了最新的<上帝之眼>全部答案,并且和玩家一起解析在案件里面的全部线索.属于<犯罪大师上帝之眼答案最新>的剧情为玩家带来了非常精彩的玩法,每一条 ...

  9. Vijos P1848 记数问题【进制】

    描述 试计算在区间 1 到 n 的所有整数中,数字 x(0 ≤ x ≤ 9)共出现了多少次?例如,在 1 到 11 中,即在 1.2.3.4.5.6.7.8.9.10.11 中,数字 1 出现了 4 ...

  10. python绘制月亮_用python画月亮的代码是什么?

    用python画月亮的代码是什么? 用python画月亮的代码是import turtle as t t.screensize(800,600,"#483d8b")#画布尺寸和颜色 ...

最新文章

  1. 李彦宏/王坚/王传福等上榜“中国工程院2019院士增选候选人”引争议,实至名归吗?...
  2. JavaPairRDD方法中几种存储方式的坑
  3. HDU-1316 How Many Fibs? Java
  4. Arduino的光敏传感器和超声波测距传感器测试代码
  5. 客户端相关知识学习(三)之Android原生与H5交互的实现
  6. windows下学习linux,在Windows环境下学习Linux命令行的几种方法
  7. 接受拒绝算法_通过算法拒绝大学学位
  8. MFCWinInet学习
  9. android支付 form表单,支付宝小程序表单组件 表单·Form
  10. java商城系统设计-----积分商城系统
  11. USB转串口那些事儿—串口驱动类型
  12. php公众号开发文档,微信公众平台的开发者文档
  13. Linux磁盘配额教程,磁盘配额设置及使用
  14. STL之容器deque
  15. 百度超级链联合超级账本:区块链技术如何提升金融行业互信与安全
  16. 2022-2028全球LED气球灯行业调研及趋势分析报告
  17. Maven导入依赖时jar包出现unknown
  18. matlab变量与常量、数据类型
  19. 赛迪中国ECM市场报告解读二:鸿翼等国内厂商正在逐步取代跨国企业
  20. 创星c1语言设置,推荐款中学生用的老年机

热门文章

  1. 掌上军营服务器信息,智慧军营之视频监控系统
  2. 从哲学的视角看待项目生命周期——构建不一样的世界
  3. 测试点击屏幕次数的软件_一款让安卓手机更好用的软件——fooView
  4. 深度学习数据增强(data_augmentation):Keras ImageDataGenerator
  5. C语言数组比较相等memcmp,使用memcmp比较两个变量结果一定吗?
  6. 无线桥接怎么设置网关和dns服务器,两个无线路由器进行桥接的设置方法
  7. matlab special,matlab的special函数用法
  8. 妖怪,你可认得这32个关键字?
  9. 计算机演示文稿实验报告,演示文稿实验报告.doc
  10. 奥斯汀计算机专业排名,德克萨斯大学奥斯汀分校计算机工程类专业排名