zoukankan      html  css  js  c++  java
  • 七天使的通讯

    【问题描述】

    n个天使排成一条直线,某些天使之间需要互相联系,他们之间的通讯可以通过黑白两种通道中的一种;所有通道必须在直线同侧(另一侧是地面);为了保证通讯效率,同种颜色的所有通道之间不能相交。请计算能否建立这种通讯方案。

    【输入】

    第一行一个数T,表示接下来有T个询问。
    对于每个询问:第一行两个数n,m,分别表示有n个天使、需要建立通讯线路的天使有m对;接下来有m行,每行两个数a、b,表示a、b两个天使需要通讯。

    【输出】

    对于每个询问,输出一行“sane”表示有可行方案、“non”表示无解。

    【输入输出样例】

    angelus.in
    1
    7 5
    1 3
    2 7
    3 4
    7 4
    6 5
    angelus.out
    sane

    【样例解释】

    样例中共有一个询问。

    在(1,3)、(4,7)、(5,6)之间连黑色通道,在(2,7)、(3,4)之间连白色通道,每条通道都成功建立,且同种颜色的通道没有相交,所以输出sane。

    【数据规模和约定】

    对于 20%的数据,1<=n<=50,1<=m<=15
    对于 50%的数据,1<=n<=1000,1<=m<=300
    对于 100%的数据,1<=n<=5000,1<=m<=1000,1<=T<=10,1<=a<=n,1<=b<=n
    数据保证每对(a,b)不重复,且a不等于b

    【提示】

    当两条线路有一对相同的端点时,这两条线路不相交。
    也就是说,对于线路(a,b)和线路(c,d)(a < b且c < d),当且仅当 a < c < b < d 或者 c < a < d < b 时这两条线路相交。

    【题解】

    先吐槽一下数据之水,我用这个贪心算法(错误解法)有80分。

    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #define fp(i,a,b) for(int i=a;i<=b;i++)
    #define fq(i,a,b) for(int i=a;i>=b;i--)
    #define il inline
    #define ll long long 
    using namespace std;
    int n,m,BL=0,BR=0,WR=0,WL=0;
    bool flagw=0,flagb=0,flag=0;
    struct line
    {
        int l,r;
    }a[1005];
    il int gi()
    {
       int x=0;
       short int t=1;
       char ch=getchar();
      while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
      if(ch=='-') t=-1,ch=getchar();
      while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
      return x*t;
    }
    bool cmp(line x,line y)
    {
        return (x.l<y.l)||(x.l==y.l&&x.r<y.r);
    }
    int main()
    {
        freopen("angelus.in","r",stdin);
        freopen("angelus.out","w",stdout);
        int t=gi();
        fp(i,1,t)
        {
            n=gi();m=gi();
            fp(i,1,m)
            {
                a[i].l=gi(),a[i].r=gi();
                if(a[i].l>a[i].r) swap(a[i].l,a[i].r);
            }
            BL=0,BR=0;
            flagw=1;flagb=1;flag=1;
            sort(a+1,a+1+m,cmp);
            WL=a[1].l,WR=a[1].r;
            fp(i,2,m)
            {
                if((a[i].l<BL&&BL<a[i].r&&a[i].r<BR)||(BL<a[i].l&&a[i].l<BR&&BR<a[i].r)) flagb=0;
                if((a[i].l<WL&&WL<a[i].r&&a[i].r<WR)||(WL<a[i].l&&a[i].l<WR&&WR<a[i].r)) flagw=0;
                if(flagw) {WL=a[i].l;WR=a[i].r;continue;}
                if(flagb) {BL=a[i].l;BR=a[i].r;continue;}
                flag=0;printf("non
    ");break;
            }
            if(flag) printf("sane
    ");
        }
        fclose(stdin);
        fclose(stdout);
        return 0;
    }

    将每个通道设为一个节点,先暴力判断每两条通道如果是同种颜色会不会相交,如果会相交就在这两个节点之间连无向边,说明它们不能为同种颜色(必须在二分图两边)。然后对组成的无向图进行二分图判定(DFS染色),寻找其中是否有相邻两点颜色相同。如果染色成功(无上述情况)说明该图是一个二分图,即有解,否则无解。

    另外,让我有点纠结的是为什么相邻两点颜色相同就不行。但想想也就明白了,一条通道为一个节点,如果两节点相邻即通道相交,不同颜色通道不能相交,解决问题。

    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #define fp(i,a,b) for(int i=a;i<=b;i++)
    #define fq(i,a,b) for(int i=a;i>=b;i--)
    #define il inline
    #define ll long long 
    using namespace std;
    int n,m,a[1005],b[1005],head[1005],cnt,ans,color[1005];
    struct edge
    {
        int to,next;
    }d[2000005];
    il int gi()
    {
       int x=0;
       short int t=1;
       char ch=getchar();
      while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
      if(ch=='-') t=-1,ch=getchar();
      while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
      return x*t;
    }
    void add(int u,int v)
    {
        d[cnt]=(edge){v,head[u]};head[u]=cnt++;
        d[cnt]=(edge){u,head[v]};head[v]=cnt++;
    }
    void dfs(int u,int fa)//判断是否有相邻两点颜色相同
    {
        if(!ans) return;
        for(int e=head[u];e!=-1;e=d[e].next)
        {
            int v=d[e].to;
            if(color[v]!=-1&&color[v]==color[u])//如果有相邻两点颜色相同,则无解
            {
                ans=0;
                return;
            }
            if(color[v]!=-1) continue;//color标过色,说明这个点搜过,跳过
            color[v]=!color[u];//尽量给相邻两点染不同颜色
            dfs(v,u);
        }
    }
    int main()
    {
        freopen("angelus.in","r",stdin);
        freopen("angelus.out","w",stdout);
        int t=gi();
        while(t--)
        {
            n=gi();m=gi();
            memset(color,-1,sizeof(color));
            memset(head,-1,sizeof(head));
            cnt=0;ans=1;
            fp(i,1,m)
            {
                a[i]=gi(),b[i]=gi();
                if(a[i]>b[i]) swap(a[i],b[i]);
                for(int j=1;j<i;j++)
                    if(a[i]<a[j]&&a[j]<b[i]&&b[i]<b[j]) add(i,j);
                    else if(a[j]<a[i]&&a[i]<b[j]&&b[j]<b[i]) add(i,j);//如上题解思想
            }
            fp(i,1,m)
              if(color[i]==-1) color[i]=0,dfs(i,0);//color为-1代表未标颜色,0,1代表两种颜色
            ans ? printf("sane
    ") : printf("non
    ");
        }
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
    
  • 相关阅读:
    大数据问题集锦
    分析JMeter聚合报告中的各项指标
    Jmeter之正则表达式提取器应用
    mysql忘记密码怎么办?
    ARIMA模型
    ADF检验
    第13章 时间序列分析和预测
    pandas的基本功能
    pandas库
    PS常用快捷键
  • 原文地址:https://www.cnblogs.com/yanshannan/p/7392293.html
Copyright © 2011-2022 走看看