zoukankan      html  css  js  c++  java
  • Ural_1169_Pairs

    此题略坑。。。

    思路:把N个点分成m若干个联通子图,然后用m-1个桥把这m个联通子图连接起来即可。

    若每个联通子图内部都是完全图也符合题意,但答案却是Wrong Answer,只有把每个联通子图内部当成环来输出才通过,这是本题的一个坑,一个Bug!!!

    另外联通子图中点的个数不能等于2(如果不明白请读者认真思考5遍)

    第三个要注意的地方就是输出时每个联通子图只能有一个点与外界连接,不能有两个!!!(如果不明白请读者认真思考10遍)

    关键在于确定每个联通子图中点的个数,若第i个联通子图中的点个数为a[i],则Σa[i]=N,且Σ(a[i]*(n-a[i]))=2K

    即Σa[i]=N- 2K ,Σa[i]=N

    方法有两种:DP 和 搜索

    DP:

    set<int>s[105];

    s[i]是和为i的若干个数的平方和的集合。

    dp[105][10005]

    若干个数和为i,平方和为j,则dp[i][j]为这些数中最大的那个

         s[0].insert(0);
         for (int i=0;i<100;++i)
             for (set<int>::iterator it=s[i].begin();it!=s[i].end();++it)
                 for (int j=i?dp[i][*it]:1;j<=100-i;++j)
                 {
                     if (j==2) continue;
                     s[i+j].insert((*it)+j*j);
                     dp[i+j][(*it)+j*j]=j;
                 }
    

      

    搜索:

    找出一组数,和为N,平方和为N- 2K :

    若找到了这样的一组数,返回数的个数,否则返回0

     int check(int x,int n,int depth)
     {
         if (n*n<x) return 0;
         for (int i=(depth>1)?a[depth-1]:1;i<=n && x-i*i>=n-i;++i)
         {
             if (i==2) continue;
             a[depth]=i;
            if (i==n && i*i==x) return depth;
             int y=check(x-i*i,n-i,depth+1);
             if (y) return y;
         }
         return 0;
     }
    

      

    完整代码如下:

    DP版:

    /*************************************************************************
        > File Name: D.cpp
        > Author: Chierush
        > Mail: qinxiaojie1@gmail.com 
        > Created Time: 2013年08月02日 星期五 09时05分46秒
     ************************************************************************/
    
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <set>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <map>
    #include <cmath>
    #include <algorithm>
    
    #define LL long long
    #define LLU unsigned long long
    
    using namespace std;
    
    int a[101],cnt;
    int dp[105][10005];
    
    set<int>s[105];
    
    int main()
    {
        s[0].insert(0);
        for (int i=0;i<100;++i)
            for (set<int>::iterator it=s[i].begin();it!=s[i].end();++it)
                for (int j=i?dp[i][*it]:1;j<=100-i;++j)
                {
                    if (j==2) continue;
                    s[i+j].insert((*it)+j*j);
                    dp[i+j][(*it)+j*j]=j;
                }
        int n,k;
        scanf("%d%d",&n,&k);
        int x=n*n-2*k;
        if (x<n)
        {
            puts("-1");
            return 0;
        }
        if (!dp[n][x]) puts("-1");
        else
        {
            int p=n,q=x;
            for (;;)
            {
                if (!p || !q) break;
                int o=dp[p][q];
                a[cnt++]=o;
                p-=o,q-=o*o;
            }
            sort(a,a+cnt);
            for (int i=1;i<cnt;++i)    a[i]+=a[i-1];
            for (int i=1;i<a[0];++i) printf("%d %d
    ",i,i+1);
            if (a[0]>1) printf("%d %d
    ",1,a[0]);
            for (int i=1;i<cnt;++i)
            {
                printf("%d %d
    ",a[i-1],a[i]);
                for (int j=a[i-1]+1;j<a[i];++j) printf("%d %d
    ",j,j+1);
                if (a[i]-a[i-1]>1) printf("%d %d
    ",a[i-1]+1,a[i]);
            }
        }
        return 0;
    }

    搜索版:

    /*************************************************************************
        > File Name: D.cpp
        > Author: Chierush
        > Mail: qinxiaojie1@gmail.com 
        > Created Time: 2013年08月02日 星期五 09时05分46秒
     ************************************************************************/
    
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <set>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <map>
    #include <cmath>
    #include <algorithm>
    
    #define LL long long
    #define LLU unsigned long long
    
    using namespace std;
    
    int a[101],cnt;
    
    int check(int x,int n,int depth)
    {
        if (n*n<x) return 0;
        for (int i=(depth>1)?a[depth-1]:1;i<=n && x-i*i>=n-i;++i)
        {
            if (i==2) continue;
            a[depth]=i;
            if (i==n && i*i==x) return depth;
            int y=check(x-i*i,n-i,depth+1);
            if (y) return y;
        }
        return 0;
    }
    
    int main()
    {
        int n,k;
        scanf("%d%d",&n,&k);
        int x=n*n-2*k;
        if (x<n)
        {
            puts("-1");
            return 0;
        }
        int u=check(x,n,1);
        if (!u) puts("-1");
        else
        {
            for (int i=2;i<=u;++i) a[i]+=a[i-1];
            for (int i=1;i<a[1];++i)
                printf("%d %d
    ",i,i+1);
            if (a[1]>1) printf("%d %d
    ",1,a[1]);
            for (int i=2;i<=u;++i)
            {
                printf("%d %d
    ",a[i-1],a[i]);
                for (int j=a[i-1]+1;j<a[i];++j)
                    printf("%d %d
    ",j,j+1);
                if (a[i]-a[i-1]>1) printf("%d %d
    ",a[i-1]+1,a[i]);
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    Redis宣言
    软件工程
    分布式编程
    编程泛型
    tcp/ip高效编程总结
    IP协议详解
    gevent程序员指南
    网站架构
    这些话,是乔布斯给世间留下的真正伟大礼物
    Flink/Spark 如何实现动态更新作业配置
  • 原文地址:https://www.cnblogs.com/Chierush/p/3232723.html
Copyright © 2011-2022 走看看