1. 程式人生 > >九度OJ 1251:序列分割 (DFS)

九度OJ 1251:序列分割 (DFS)

時間限制:1 秒

記憶體限制:32 兆

特殊判題:

提交:166

解決:34

題目描述:

一個整數陣列,長度為n,將其分為m份,使各份的和相等,求m的最大值
  比如{3,2,4,3,6} 可以分成{3,2,4,3,6} m=1;
  {3,6}{2,4,3} m=2
  {3,3}{2,4}{6} m=3 所以m的最大值為3。

輸入:

存在多組資料,每組資料一定行為一個正整數n(n<=64),第二行為n個數字。當n為0時,測試結束。

輸出:

輸出最大值m。

樣例輸入:
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0
樣例輸出:
4 
2

思路:

剪枝1:由大到小順序排列,每次選擇重上次選擇的後一個開始。
剪枝2:如果一個數字把一組填滿了,不需要考慮用更小的木棍填補這一組了,進行對下一組的搜尋。
剪枝3:設對一組的搜尋開始時,當前尚未用的最大的數字是a,如果把a選入不行,那麼目前的狀態應捨棄,因為這個數字a是必然要處理的,而放到後面處理,只會可用數字更少,而亦必然不可以。
剪枝4:由於數字已排序,前面一個數字嘗試後不行,則跳過下面同樣的數字。
這個題目很經典。黑書上有講過,但其只錯誤的強調了剪枝2的效用,而事實上剪枝3是最強且必須的,需要注意。

程式碼:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int cmp(const void *a, const void *b) {
    return (*(int *)a < *(int *)b) * 2 - 1;
}

int n, A[100], sum;
int mark[100], ans, full;


int dfs(int cnt, int max, int re, int s) {
    if (cnt == 0) return 1;

    if (re == 0) {
        return dfs(cnt-1, max, max, 0);
    }

    int i;
    for (i=s; i<n; i++) {
        if (mark[i] || re-A[i] < 0) continue;

        mark[i] = 1;
        if (dfs(cnt, max, re-A[i], i+1)) return 1;
        mark[i] = 0;

        if (re-A[i] == 0) break;

        if (max == re) break; //the largest number have try, and failed, cut

        // not sucess, skip the same number
        while (A[i+1] == A[i] && i+1<n) i++;

    }

    return 0;
}


int Try(int len) {
    if (sum % len != 0) return 0;

    memset(mark, 0, sizeof mark);
    return dfs(sum/len, len, len, 0);
}


void Solve() {
    qsort(A, n, sizeof(int), cmp);

    int m = A[0];
    while (!Try(m)) m++;

    printf("%d\n", sum/m);
}


int main()
{
    int i, j;

    while (scanf("%d", &n), n) {
        for (sum=i=0; i<n; i++)
            scanf("%d", &A[i]), sum+=A[i];
        Solve();
    }
    return 0;
}


相關推薦

OJ 1251序列分割 DFS

時間限制:1 秒 記憶體限制:32 兆 特殊判題:否 提交:166 解決:34 題目描述: 一個整數陣列,長度為n,將其分為m份,使各份的和相等,求m的最大值   比如{3,2,

OJ 1052找x 基礎題

時間限制:1 秒 記憶體限制:32 兆 特殊判題:否 提交:7335 解決:3801 題目描述: 輸入一個數n,然後輸入n個數值各不相同,再輸入一個值x,輸出這個值在這個陣列中的

OJ 1133學分績點 加權平均數

時間限制:1 秒 記憶體限制:32 兆 特殊判題:否 提交:1333 解決:702 題目描述: 北京大學對本科生的成績施行平均學分績點制(GPA)。既將學生的實際考分根據不同的學

OJ 1014排名 排序

時間限制:1 秒 記憶體限制:32 兆 特殊判題:否 提交:8267 解決:2469 題目描述:     今天的上機考試雖然有實時的Ranklist,但上面的排名只是根據完成的題數

OJ 1008最短路徑問題 最短路

時間限制:1 秒 記憶體限制:32 兆 特殊判題:否 提交:8064 解決:2685 題目描述: 給你n個點,m條無向邊,每條邊都有長度d和花費p,給你起點s終點t,要求輸出起點到終點的最短距離及其花費,如果最短距離有多條路線,則輸出花費最少的。 輸入

OJ 1482瑪雅人的密碼

清華 sizeof swap name substr wap 如果 found www 題目描述: 瑪雅人有一種密碼,如果字符串中出現連續的2012四個數字就能解開密碼。給一個長度為N的字符串,(2=<N<=13)該字符串中只含有0,1,2三種數字,問這個字符串

OJ-1457非常可樂

  本題也是轉化為狀態建立解答樹並剪枝,然後進行廣度優先搜尋。 Debug記錄: ①找了很久,最後發現是mark陣列的初始化除了問題,原始碼如下: for (int i=1;i<=S;i++){ for (int j=1;j<=N;j++){

OJ-120810進位制 VS 2進位制

  本題使用了寫好的高精度整數的模板,將ten2N()函式的輸出方式稍微改了改。 debug過程: ①過載的*運算通過這道題發現了bug:當輸入的int x為0時,由於使用的是BigInt與int逐位乘的演算法,故若BigInt的intSize不為1的話,會return一個

OJ 1208 10進位制 VS 2進位制

#include <stdio.h> #include <stdlib.h> #include <string.h> void swap(int *p, int *q) { int temp; temp = *p; *p = *q; *

OJ 1081 遞推數列

#include <stdio.h> #include <stdlib.h> #define MOD 10000 //結果取MOD,避免高精度運算 /*將矩陣p與矩陣q相乘,結果存入p矩陣*/ void Matrix_mul(int p[2][2], int q[2][

OJ-1450產生冠軍

  這道題厲害了。= =想不明白 演算法分析:   由於這裡的優先關係具有傳遞性,故可利用有向圖表示優先關係:“A優勝於C”==可抽象為==》“A到C之間存在有向路徑”。有了這層抽象就能進行以下分析: ①“不能出現迴圈優先關係”《==》不能出現環路:進行拓撲排序來檢測有無環

OJ 1455 珍惜現在,感恩生活

#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct Food //糧食結構體 { int price; int wei

題目1251序列分割(DFS+剪枝)

題目描述: 一個整數陣列,長度為n,將其分為m份,使各份的和相等,求m的最大值   比如{3,2,4,3,6} 可以分成{3,2,4,3,6} m=1;   {3,6}{2,4,3} m=2   {3,3}{2,4}{6} m=3 所以m的最大值為3。 輸入: 存在多

OJ-1144Freckles

  依然是最小生成樹問題,使用並查集+kruskal實現。不贅述。 題目描述:     In an episode of the Dick Van Dyke show, little Richie connects the freckles on his Dad's b

OJ 1003A+B

時間限制:1 秒 記憶體限制:32 兆 特殊判題:否 提交:15078 解決:6299 題目描述: 給定兩個整數A和B,其表示形式是:從個位開始,每三位數用逗號","隔開。 現在請

OJ 1088 剩下的樹

#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { int l, m; while(scanf("%d%d", &l, &m) != EOF)

Oj 1123 採藥

題目描述: 辰辰是個很有潛能、天資聰穎的孩子,他的夢想是稱為世界上最偉大的醫師。 為此,他想拜附近最有威望的醫師為師。醫師為了判斷他的資質,給他出了一個難題。 醫師把他帶到個到處都是草藥的山洞裡對他說: “孩子,這個山洞裡有一些不同的草藥,採每一株都需要一些時間,每一株也

資料結構實驗之棧與佇列十走迷宮DFS

Problem Description 一個由n * m 個格子組成的迷宮,起點是(1, 1), 終點是(n, m),每次可以向上下左右四個方向任意走一步,並且有些格子是不能走動,求從起點到終點經過每個格子至多一次的走法數。 Input        第一行一個整數T

洛谷1101單詞方陣DFS

題目描述 給一n×nn \times nn×n的字母方陣,內可能蘊含多個“yizhong”單詞。單詞在方陣中是沿著同一方向連續擺放的。擺放可沿著888個方向的任一方向,同一單詞擺放時不再改變方向,單詞與單詞之間可以交叉,因此有可能共用字母。輸出時,將不是單詞的字

OJ 題目1008最短路徑問題 Dijstra 演算法

題目描述: 給你n個點,m條無向邊,每條邊都有長度d和花費p,給你起點s終點t,要求輸出起點到終點的最短距離及其花費,如果最短距離有多條路線,則輸出花費最少的。 輸入: 輸入n,m,點的編號是1~n,然後是m行,每行4個數 a,b,d,p,表示a和b之間有一條邊,且其長度為