cf 366D D. Dima and Trap Graph (计算所有线段共同覆盖的某段区间)

http://codeforces.com/problemset/problem/366/D

题意:给出n个点,m条边,a,b,ll,rr分别代表点a,点b相连,点a和点b的区间范围(ll,rr),然后让你选择边相连接使得可以从点1到点n,并且所有被选择的边所共同覆盖的区间范围最大。

4 4
1 2 1 10
2 4 3 5
1 3 1 5
2 4 2 7
6
4个点,4条边,现在可以从1--2--4,存在两条路径,(1,10)--(3,5)或者(1,10)——(2,7),要选择这所共同覆盖的区间范围最大的路径,那么就是(1,10)——(2,7),所覆盖的区间范围为7-2+1

若是最大区间范围没有,输出-1;

思路:仔细思考过后,会发现,其实若存在最大共同覆盖区间(p),那么区间p的左极限必然是某个区间的左端点,区间p的右极限必然是某个区间的右端点,当然这“某个区间”,可能会是一个区间,也可能会是两个区间......

如此的话,我是对所有区间按ll排序,然后枚举rr区间,找ll,用并查集判断是否可以从点1到点n.....可是wa多次......至今没有弄明白,是哪个地方思路问题?

wa代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;

struct node
{
    int v1,v2;
    int x,y;
    //int len;
} s[3*1005];
int father[3000];
int n,m;
int vist[1005],flg1,flg2,ans,xx,yy;
int cmp(const node a,const node b)
{
    if(a.x<b.x)
        return 1;
    else
        return 0;
}
int find(int x)
{
    int root,i=x;
    while(x!=father[x])
        x=father[x];
    root=x;
    x=i;
    while(x!=father[x])
    {
        i=father[x];
        father[x]=root;
        x=i;
    }
    return root;
}

int main()
{
    while(scanf("%d%d",&n,&m)>0)
    {
        for(int i=0; i<m; i++)
        {
            scanf("%d%d%d%d",&s[i].v1,&s[i].v2,&s[i].x,&s[i].y);
            //s[i].len=s[i].y-s[i].x+1;
        }
        sort(s,s+m,cmp);
        ans=0;
        for(int i=0; i<m; i++)
        {
            for(int j=0; j<=n; j++)
                father[j]=j;
            for(int j=0;j<m;j++)
            {
                if(s[i].y<s[j].x)
                break;
                if(s[j].x>s[i].x)
                continue;
                if(s[i].x>s[j].y)
                continue;
                int s1=find(s[j].v1);
                int s2=find(s[j].v2);
                if(s1!=s2)
                {
                    father[s1]=s2;
                }
                if(find(1)==find(n))
                {
                    if(ans<s[j].y-s[i].x+1)
                    ans=s[j].y-s[i].x+1;
                    //printf("%d %d\n",s[i].x,s[i].y);
                }
            }
        }
        if(ans==0)
            printf("Nice work, Dima!\n");
        else
            printf("%d\n",ans);
    }
    return 0;
}

 然后,我依旧是对ll排序,但是这次是枚举rr来找ll,依旧是并查集判断是否联通1到n,额,ac了......有点不可思议,思考ing

ac代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;

struct node
{
    int v1,v2;
    int x,y;
    //int len;
} s[3*1005];
int father[3000];
int n,m;
int vist[1005],flg1,flg2,ans,xx,yy;
int cmp(const node a,const node b)
{
    if(a.x<b.x)
        return 1;
    else
        return 0;
}
int find(int x)
{
    int root,i=x;
    while(x!=father[x])
        x=father[x];
    root=x;
    x=i;
    while(x!=father[x])
    {
        i=father[x];
        father[x]=root;
        x=i;
    }
    return root;
}

int main()
{
    while(scanf("%d%d",&n,&m)>0)
    {
        for(int i=0; i<m; i++)
        {
            scanf("%d%d%d%d",&s[i].v1,&s[i].v2,&s[i].x,&s[i].y);
            //s[i].len=s[i].y-s[i].x+1;
        }
        sort(s,s+m,cmp);
        ans=0;
        for(int i=0; i<m; i++)
        {
            for(int j=0; j<=n; j++)
                father[j]=j;

            for(int j=0;j<m;j++)
            {
                if(s[i].y<s[j].x)
                break;
                if(s[i].y>s[j].y)
                continue;
                //if(s[j].x>s[i].x)
                //continue;
                int s1=find(s[j].v1);
                int s2=find(s[j].v2);
                if(s1!=s2)
                {
                    father[s1]=s2;
                }
                //printf("%d %d\n",s[j].v1,s[j].v2);
                if(find(1)==find(n))
                {

                    if(ans<s[i].y-s[j].x+1)
                    ans=s[i].y-s[j].x+1;
                    break;
                }
            }
        }
        if(ans==0)
            printf("Nice work, Dima!\n");
        else
            printf("%d\n",ans);
    }
    return 0;
}

 经过思考,我觉得wa代码是因为rr无序,也就是说,我只对ll排序了,枚举ll所找到的rr是无规律的,导致本来有些区间是应该会先连通点1到点n的,而因为rr无序,扰乱了.....所以wa,额,为了验证是不是这样的,便有了接下来的代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;

struct node
{
    int v1,v2;
    int x,y;
    //int len;
} s[3*1005];
int father[3000];
int n,m;
int vist[1005],flg1,flg2,ans,xx,yy;
int cmp(const node a,const node b)
{
    if(a.y>b.y)
        return 1;
    else
        return 0;
}
int find(int x)
{
    int root,i=x;
    while(x!=father[x])
        x=father[x];
    root=x;
    x=i;
    while(x!=father[x])
    {
        i=father[x];
        father[x]=root;
        x=i;
    }
    return root;
}

int main()
{
    while(scanf("%d%d",&n,&m)>0)
    {
        for(int i=0; i<m; i++)
        {
            scanf("%d%d%d%d",&s[i].v1,&s[i].v2,&s[i].x,&s[i].y);
            //s[i].len=s[i].y-s[i].x+1;
        }
        sort(s,s+m,cmp);
        ans=0;
        for(int i=0; i<m; i++)
        {
            for(int j=0; j<=n; j++)
                father[j]=j;

            for(int j=0;j<m;j++)
            {
                if(s[i].x>s[j].y)
                continue;
                if(s[i].y<s[j].x)
                continue;
                //if(s[i].x)
                if(s[j].x>s[i].x)
                continue;
                int s1=find(s[j].v1);
                int s2=find(s[j].v2);
                if(s1!=s2)
                {
                    father[s1]=s2;
                }
                //printf("%d %d\n",s[j].v1,s[j].v2);
                if(find(1)==find(n))
                {

                    if(ans<s[j].y-s[i].x+1)
                    ans=s[j].y-s[i].x+1;
                    break;
                }
            }
        }
        if(ans==0)
            printf("Nice work, Dima!\n");
        else
            printf("%d\n",ans);
    }
    return 0;
}

 ac了......真是这样的哈......

具体的来说,我觉得解一道题目,不仅仅只是ac了就可以的........

这道题目,对于区间的排序问题,有讲究的。比如说只有四个点的情况,1 2  1  10与2  4  2  7;
表示点1和点2相连,区间值为1--10,点2与点4相连,区间值为2--7;

现在按区间的ll从小到大排序:

s[0].v1=1   s[0].v2=2   s[0].ll=1   s[0].rr=10;

s[1].v1=2   s[1].v2=4   s[1].ll=2   s[1].rr=7;

若枚举ll来确定rr,那么就会出现10-2+1的输出,其实为什么会这样?自己在纸上动手画画就可以明白;

但枚举rr来确定ll,却不会产生这样的情况......

 

同理,若是按照区间rr从大到小排序,然后枚举ll来确定rr,也会是正确的.......至于为什么一种要从小到大,而另一种要从大到小,找两个这样的区间,一个区间被另一个区间包含,然后动手画画,就可以明白........

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值