zoukankan      html  css  js  c++  java
  • D

     Degree Set
    time limit per test
    2 seconds
    memory limit per test
    256 megabytes
    input
    standard input
    output
    standard output

    You are given a sequence of n positive integers d1, d2, ..., dn (d1 < d2 < ... < dn). Your task is to construct an undirected graph such that:

    • there are exactly dn + 1 vertices;
    • there are no self-loops;
    • there are no multiple edges;
    • there are no more than 106 edges;
    • its degree set is equal to d.

    Vertices should be numbered 1 through (dn + 1).

    Degree sequence is an array a with length equal to the number of vertices in a graph such that ai is the number of vertices adjacent toi-th vertex.

    Degree set is a sorted in increasing order sequence of all distinct values from the degree sequence.

    It is guaranteed that there exists such a graph that all the conditions hold, and it contains no more than 106 edges.

    Print the resulting graph.

    Input

    The first line contains one integer n (1 ≤ n ≤ 300) — the size of the degree set.

    The second line contains n integers d1, d2, ..., dn (1 ≤ di ≤ 1000, d1 < d2 < ... < dn) — the degree set.

    Output

    In the first line print one integer m (1 ≤ m ≤ 106) — the number of edges in the resulting graph. It is guaranteed that there exists such a graph that all the conditions hold and it contains no more than 106 edges.

    Each of the next m lines should contain two integers vi and ui (1 ≤ vi, ui ≤ dn + 1) — the description of the i-th edge.

    Examples
    input
    Copy
    3
    2 3 4
    output
    Copy
    8
    3 1
    4 2
    4 5
    2 5
    5 1
    3 2
    2 1
    5 3
    input
    Copy
    3
    1 2 3
    output
    Copy
    4
    1 2
    1 3
    1 4
    2 3

    题意:给出无向图所有节点的度组成的集合(集合默认从大到小并且不重复),且无向图中无重边自环,节点数为最高度+1。询问一种构造方式能构造出一个符合上述度集以及要求的图,输出所有的边。保证一定有这样的图存在。
     
    题解:保证存在那就直接莽,别慌。设总节点数为dn+1dn+1。设我们从度集左右两边以及按照编号大小两边同时构造这个图。首先r为当前和其他点连边的结点点,l为r所可以连接到的编号最低的结点,即每次我们都将r与[l,r-1]连边。那么我们的r结点连完以后有dn+2ldn+2−l的度(r右侧的结点都是有跟r连边的)。按编号两边构造的意思是我们每次构造出指定要求的度数点后l要增加,r要减少。设rt为度集最右侧的还未出现过的度数下标drtdrt即为该度数,lt为度集最左侧的还未出现过的度数下标dltdlt即为该度数。那我们每次构造就要构造出一对drtdltdrt和dlt 然后lt++,rt--。
        对dltdlt构造,那么我们需要dn+1到 dn+1dlt 号r侧的点实行上述的连边操作,那么l的结点的度就会达到要求的dltdlt。那么假如现在 l 的度数为 degreel ,那么我们只需要 [rdltdegreel+1,r][r−dlt−degreel+1,r] 这些点实行上述的连边操作,那么[l,rdltdegreel][l,r−dlt−degreel] 的结点度数都会变为dltdlt ,然后把r更新为rdltdegreelr−dlt−degreel。因此不难看出其实原来的 degreeldegreel 是 dlt1dlt−1。然后就是 drtdrt 的构造了。上面我们说每个r连到 l 有 dn+2ldn+2−l的度,因此我们每次构造 dltdlt前,把 l 增加到(更新为)dn+1drtdn+1−drt ,那么就能保证上述连边的这些r他们的度数为drtdrt。这样不断操作直到rt<ltrt<lt 就能构造出符合要求的图。
     
    #include<bits/stdc++.h>
     #define clr(x) memset(x,0,sizeof(x))
     #define mod 1000000007
     #define clr_1(x) memset(x,-1,sizeof(x))
     #define INF 0x3f3f3f3f
     #define LL long long
     #define pb push_back
     #define pbk pop_back
     using namespace std;
     const int N=3e3+10;
     int a[N];
     vector<int> dt[N];
     int rt,n,p,lt,r,l,ans;
     int main()
     {
         scanf("%d",&n);
         for(int i=1;i<=n;i++)
             scanf("%d",a+i);
         for(int i=1;i<=a[n]+1;i++)
             dt[i].clear();
         rt=n;
         r=a[n]+1;
         lt=1;
         l=1;
         while(lt<=rt)
         {
             while(dt[l].size()<a[lt])
             {
               for(int j=l;j<r;j++)
                     dt[j].pb(r);
                 r--;
             }
             rt--;
             lt++;
             l=a[n]+1-a[rt];
         }
         ans=0;
         for(int i=1;i<=a[n]+1;i++)
             ans+=dt[i].size();
         printf("%d
    ",ans);
         for(int u=1;u<=a[n]+1;u++)
         {
             for(auto v:dt[u])
                 printf("%d %d
    ",u,v);
         }
         return 0;
    }
    //双指针
    /* LittleFall : Hello! */
    #include <bits/stdc++.h>
    typedef long long ll;
    using namespace std;
    inline int read();
    inline void write(int x);
    const int M = 1024;
    int save[M];
    
    int main(void)
    {
        int n=read(),ans=0;
        for(int i=1;i<=n;i++)
            save[i]=read();
        int vecs=save[n]+1;
    
        int r=n,l=1,ready=0;
        for(int vec=1;vec<vecs;vec++)
        {
            if(save[l]<=ready)
                l++,r--;    
            else if(ready+vecs-vec==save[r])
                ready++,ans+=vecs-vec;
        }
        printf("%d
    ",ans );
    
        r=n,l=1,ready=0;
        for(int vec=1;vec<vecs;vec++)
        {
            if(save[l]<=ready)
                l++,r--;
            else if(ready+vecs-vec==save[r])
            {
                for(int j=vec+1;j<=vecs;j++)
                    printf("%d %d
    ",vec,j );
                ready++;
                ans+=vecs-vec;
            }
        }
    
        return 0;
    }
    
    
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void write(int x)
    {
         if(x<0) putchar('-'),x=-x;
         if(x>9) write(x/10);
         putchar(x%10+'0');
    }
  • 相关阅读:
    0909初识操作系统
    实验四主存空间的分配和回收
    实验一 DOS命令解释程序的编写
    0909关于操作系统
    实验四主存空间的分配和回收
    实验3评价
    实验一 DOS命令解释程序的编写
    实验三、进程调度模拟程序实验
    实验二、作业调度实验
    0909 第一次上机课之《为什么学操作系统?》
  • 原文地址:https://www.cnblogs.com/upstart/p/8982436.html
Copyright © 2011-2022 走看看