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 }
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 }