ZOJ Problem Set - 1239 (最小点覆盖 )

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=239

337这个题普通的方法或打表就可以过,在这里主要是用最小路径覆盖思想解一下。这题需要转化一下,将问题从求m根柱子最多能放多少球,变为,n个球最少 需要多少柱子。如果对i<j,i + j 为完全平方数,则有一条从i到j的有向边,就变成了求图的最小路径覆盖。这时候只要在预处理中把最小路径覆盖小于50的全部算出来就可以了。

求最 小路径覆盖一般是转化为求图的二分匹配,但是要对图进行一些转化,构造一个新图。将节点i分裂为两个节点i, i',如果原图中有从i到j的节点,则新图中有从i到j'的边,其实就是将一个点分为入点、出点,去除掉同一路径上不可以同时匹配相邻节点的限制,保证二 分匹配和最小路径覆盖一一对应,此时,满足公式:原图最小路径覆盖 = 原图顶点数 - 最大二分匹配。


  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cmath>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<set>
  7 #include<map>
  8 #include<queue>
  9 #include<vector>
 10 #include<string>
 11 #define Min(a,b) a<b?a:b
 12 #define Max(a,b) a>b?a:b
 13 #define CL(a,num) memset(a,num,sizeof(a));
 14 #define eps  1e-6
 15 #define inf 10001000
 16 
 17 #define ll   __int64
 18 
 19 #define  read()  freopen("data.txt","r",stdin) ;
 20 const double pi  = acos(-1.0);
 21 const int maxn = 2000;
 22 
 23 using namespace std;
 24 int n,m;
 25 int head[maxn] ;
 26 int result[maxn],vis[maxn] ;
 27 struct node
 28 {
 29     int v;
 30     int next;
 31 }p[maxn*maxn];
 32 int mat[maxn][maxn] ;
 33 int cnt,num ;
 34 int f[maxn*2];
 35 int ans[55] ;
 36 void add(int u,int v)
 37 {
 38     p[cnt].v = v;
 39     p[cnt].next = head[u];
 40     head[u] = cnt++ ;
 41 }
 42 bool find(int u)
 43 {
 44 
 45     for(int i = 1;i <= num;i++)
 46     {
 47 
 48         if(mat[u][i]&&!vis[i])
 49         {
 50             vis[i] = 1 ;
 51             if(result[i] == -1||find(result[i]))
 52             {
 53                 result[i] = u;
 54                 return true;
 55             }
 56         }
 57     }
 58     return false ;
 59 }
 60 int get()
 61 {
 62 
 63     int ans= 0;
 64     CL(result,-1);
 65     for(int i = 1;i <= num;i++)
 66     {
 67         CL(vis,0);
 68         if(find(i))ans++;
 69     }
 70     return ans ;
 71 }
 72 void init()
 73 {
 74     int i,j;
 75     CL(f,0) ;
 76     CL(mat,0) ;
 77     //CL(head,-1) ;
 78     cnt = 0;
 79 
 80     for(i = 1 ;i*i < maxn*2;i++)
 81     {
 82          f[i*i] = 1;
 83     }
 84     for(i = 1;i<maxn;i++)
 85     {
 86         for(j = i + 1;j<maxn;j++)
 87         {
 88             if(f[i+j] ==1)mat[i][j] = 1;
 89         }
 90     }
 91 
 92     for(i = 1;i< maxn;i++)
 93     {
 94         num = i;
 95         int k = get();
 96         if(i - k > 50)break;
 97         ans[i - k] = i;
 98     }
 99 
100 
101 }
102 int main()
103 {
104     int t;
105     init() ;
106     scanf("%d",&t);
107     while(t--)
108     {
109         scanf("%d",&n);
110         printf("%d\n",ans[n]) ;
111     }
112 }
posted @ 2012-10-12 16:57  Szz  阅读(375)  评论(0)    收藏  举报