zoukankan      html  css  js  c++  java
  • [ZPG TEST 110] 多边形个数【DP】

    1. 多边形个数

    (polygons.pas/c/cpp)

    【问题描述】

    给定N线段,编号1到n。并给出这些线段的长度,用这些线段组成一个K边形,并且每个线段做多使用一次。若使用了一条不同编号的线段,即视为两个多边形不同。问一共可以组成多少个K边形的多边形。

    【输入】

    输入文件名为polygons.in。

    有多组测试数据:
    第一行,包含一个整数Num,表示测试数据的个数。(1<=Num<=10)
    每组测试数据,
    第一行一个整数N,表示共有N条线段。1<=N<=50.
    接下来一行N个整数,表示N条线段的长度[1,50000]。

    最后一个整数K[3,10]。

    【输出】

    输出文件polygons.out共Num行,
    一共可以组成多少个不同的K边形。

    【输出输出样例】

    polygons.in

    polygons.out

    5

    4

    1 1 1 1

    3

    4

    2 3 4 5

    3

    6

    4 4 4 2 2 2

    3

    5

    10 1 4 9 20

    4

    13

    3310 1660 211 1260 160 213 884 539 17212 2025 105 120 5510

    7

    4

    3

    11

    2

    532

    说实话完全没看出来是DP,还以为是一道想法题。究其原因,就是没有想到多边形的一个性质:一个N边形任意N - 1条边的和必然大于剩下那条边(类比三角形性质),这很显然。那么只要保证最小的N - 1条边的和大于最大的边,就可以构成N边形。

    这样子dp的轮廓就出来了,先把给出的线段长度从小到大排序,然后设计状态:f(i, j, k)表示考虑了前i条线段了,其中j条线段的和为k的方案数。那么f(i, j, k) = f(i - 1, j, k) + f(i - 1, j - 1, k - a[i]),这里第三维开的比50000大一点就好了,因为线段最大为50000,那么那些长度和大于50000就可以压缩到一个状态了。每计算完一个i,就把前i - 1条边的和大于a[i]的方案数全部加到ans上,最后一个选的是第i条边时,有几种方案。dp时用滚动数组。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    int T, n, a[55], kk;
    long long f[2][15][50005], ans;
    
    int main(void) {
    	freopen("polygons.in", "r", stdin);
    	freopen("polygons.out", "w", stdout);
    	scanf("%d", &T);
    	while (T--) {
    		ans = 0;
    		memset(a, 0, sizeof a);
    		memset(f, 0, sizeof f);
    		scanf("%d", &n);
    		for (int i = 1; i <= n; ++i) {
    			scanf("%d", a + i);
    		}
    		std::sort(a + 1, a + n + 1);
    		scanf("%d", &kk);
    		f[0][0][0] = 1;
    		for (int i = 1; i <= n; ++i) {
    			memcpy(f[i & 1][0], f[i & 1 ^ 1][0], sizeof f[0][0]);
    			for (int j = 1; j < kk; ++j) {
    				for (int k = 0; k < a[i]; ++k) {
    					f[i & 1][j][k] = f[i & 1 ^ 1][j][k];
    				}
    				for (int k = a[i]; k <= 50001; ++k) {
    					f[i & 1][j][k] = f[i & 1 ^ 1][j][k] + f[i & 1 ^ 1][j - 1][k - a[i]];
    				}
    				for (int k = 50002 - a[i]; k <= 50001; ++k) {
    					f[i & 1][j][50001] += f[i & 1 ^ 1][j - 1][k];
    				}
    			}
    			for (int k = a[i] + 1; k <= 50001; ++k) {
    				ans += f[i & 1 ^ 1][kk - 1][k];
    			}
    		}
    		printf("%I64d
    ", ans);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    python入门-函数(二)
    python入门-函数(一)
    python入门-WHILE循环
    python入门-用户输入
    python入门-字典
    Spring Security授权 AccessDecisionManager
    Java的性能优化
    datahub
    vbs mytest
    spring发布和接收定制的事件(spring事件传播)
  • 原文地址:https://www.cnblogs.com/ciao-sora/p/6006549.html
Copyright © 2011-2022 走看看