您的位置:首页 > 其它

图论(PolandBall and White-Red graph,cf 755E)

2017-01-16 14:25 465 查看
道理还是那么的简单,多动脑子,少动键盘。如果解法不对,写代码只是在浪费时间。如果解法正确,写代码是分分钟的事情。

1<=k<=1000

k的范围看上去那么正常,这是出题人用来迷惑你的,事实上k>3都无解。如果让自己去证明G和G的补图G'的直径不能同时>3,那么我兴许会证出来。但是如果没有这个方向感觉真的很难想到。其实所有的“很难想到”都是因为自己不熟练或者根本不会。其实现在自己有点后悔翘了图论去搞ACM,本以为自己搞ACM了后应付图论应该会小菜一碟,但是其实ACM!=算法与数据结构!=图论!=数学。在ACM中进行的训练范围太大,不够专精,从而导致自己只能应付各个课程上比较简单的问题,也只能应付ACM中各方面比较简单的问题,而且学的很浅,只会应用而无法看到本质,稍微遇到一些灵活的问题就只能不知所措。如果认真学习算法与数据结构,图论,数学等课程,那么就能够通过这些专项训练使自己能真正的弄懂那些解法背后的道理,从而在遇到一个全新的问题时能有理有据地想出一个神奇的解法,而不是靠抖机灵去想出一道题目的解法。虽然这些课程对搞ACM并没有直接的提升,但是轻视这些课程真的会非常伤,因为这会导致你绩点又不高,而且这还会成为你进一步提升的瓶颈。其实哪怕你JAVA学好了,至少也能在写高精度时也会比别人熟练很多啊。没有学好课业而去搞ACM真的是一个短视的做法,因为当你水平越来越高时,你会发现真正阻碍你进一步提升的东西正是这些深奥的理论课程,如果不专门地去练习,那么自己永远只能做简单题,遇到复杂题只能抖机灵或者看题解然后有个印象,再遇到同样的复杂题你还是只能抖个机灵。希望自己下学期至少能把《离散数学》以及《概率论与数理统计》学好。

继续讲题。

求证:图G与其补图G'的直径不能同时>3。

证明:若图G的直径>3,那么存在u,v属于V(G),使得最短路径d(u,v)>3,那么设集合S(u)与S(v)分别为u以及u的邻点的集合与v以及v的邻点的集合。由于d(u,v)>3,所以S(u)∩S(v)=∅,且S(u)∪S(v)是V(G)的真子集,即S(u)中的点与S(v)中的点不相邻。那么可以把V(G)分成两部分,V1(G)=S(u)∪S(v),V2(G)=V(G)-V1(G)。

下面证明此时G'的直径<=3。

即证明任取x,y∈V(G'),都有d(x,y)<=3。

分三种情况讨论:

①x,y∈V1(G)

我们容易得到,在G'中,S(u)与S(v)中的点都相邻,

如果x∈S(u),y∈S(v),那么x,y相邻,即d(x,y)=1。

如果x,y∈S(u),那么必存在路径x->v->y,可能存在路径x->y,即d(x,y)<=2。

同理可得,如果x,y∈S(v),d(x,y)<=2。

在这种情况下d(x,y)<=2。

②x,y∈V2(G)

我们容易得到,在G'中,V2(G)中的点与u,v都相邻。

因此必存在路径x->u->y,可能存在路径x->y,即d(x,y)<=2。

③x∈V1(G),y∈V2(G)

我们容易得到,在G'中,u与S(v)中的点都相邻,或v与S(u)中的点都相邻。

那么必存在路径x->u->y或x->v->y,可能存在路径x->y,即d(x,y)<=2。

综上所述,d(x,y)<=2。

证毕。

我是看了https://www.zhihu.com/question/42931296?from=profile_question_card

上的证明,然后写的。

证明完了以后,剩下的就是讨论+构造了。

题目中有个条件说,如果图不连通,那么直径就是-1,我理解成了如果两点不连通,那么两点距离就是-1,然后就错了。因为如果按照题目中的说法,不连通的图是一定不行的(有个定理是说G和G'不可能同时不连通,那么显然一个直径为-1另一个一定不是-1,看吧图论学了多有用)。而我的理解构造出了不连通的图。以后看题目一定要再仔细一点吧,说了一万遍了。。。其实也不光是不仔细,更是因为英语不好,所以才会半看半猜,加了很多自己的想法进去。

首先发现n=1,2,3肯定都不行。(枚举所有情况,都不行)

因为图要连通,所以图至少得是树,而且补图还得保证连通,因此k=1就一定不行。(G是树的话,G'的直径就是2了)

k>3又不行。

所以就讨论n>=4且k=2或k=3就好了。

n=4要特判一下。

其他情况:

构造k=2:

连n-1条边,分别是i连到i+1,1<=i<n。

构造k=3:

连n-1条边,分别是i连到i+1,1<=i<n-1,以及n-1连到n。

具体看代码。

代码

#include<bits/stdc++.h>
using namespace std;

int n,k;

int main()
{
scanf("%d %d",&n,&k);
if(n<=3) puts("-1");
else if(k==1) puts("-1");
else if(k>3) puts("-1");
else if(n==4)
{
if(k==2) puts("-1");
else
{
puts("3");
puts("1 2");
puts("2 3");
puts("3 4");
}
}
else if(k==2)
{
printf("%d\n",n-1);
for(int i=1;i<n;i++)
printf("%d %d\n",i,i+1);
}
else
{
printf("%d\n",n-1);
for(int i=2;i<n;i++)
printf("1 %d\n",i);
printf("%d %d\n",n-1,n);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: