TopCoder SRM 360 DIV2 500 分題目, 需要排列組合麼?需要強力法麼?

昨天晚上的比賽只做出來 250 分的題目,花了 20  分鐘,有所進步,但是後面兩題 沒做出來,rating  掉到了 926 ,唉 ~~  繼續加油吧!

下面是 500 分的題目,初以爲需要用排列組合的知識的,但是原來是不需要的,純粹是個 mathematic trick
簡要描述題意如下:
有一個矩陣,行數爲 row (不大於 20 ), 列數爲 col (不大於 20 ), 元素都是 int 類型( 不大於 50),從這個矩陣中選取一些元素,使得每一行,每一列都最多隻有一個元素被選取,將選取的元素求和爲 sum 。Larry 說,對於每一種選取的方法, sum 都相等。要求寫一個函數,判斷 Larry 的話是否正確,正確則返回  "CORRECT", 否則返回  "INCORRECT"。

如果使用強力法( brute force solution ),對於每種選取的方案都求一次和,直到所有方案測試了或者中途求出的和不一樣。假設 row >= col ,那麼時間複雜度是 O (C (row, col) * col !) = O (row ! /  (row - col) !) ,最大時可達 20 ! ,恐怕超時啦。而且還要生成組合的(我在比賽後才寫了個生成組合的函數)。
今天下午看了別人的 discuss ,才恍然大悟,寫了代碼,在 practice 裏面提交,正確!呵呵。


解題的思想是建立在這個事實上:任意一個選取的方案,稍作修改這個方案可以得到下一個方案,繼續修改,可以得到所有的方案

對於行數和列數不相等的情況,假設行數較大(反之亦然),必須每一行都相等, Larry 纔是正確的。舉個反例說,3 × 2 的矩陣,選取的元素用括號括住。這兩個方案的 sum 不相等。
(3)     7
 3     (7)
 2      8
========== sum1 = 10
(3)     7
 3      7
 2     (8)
========== sum2 = 11

對於行數和列數相等的情況,必須每兩個行(列)向量之差的各分量相等,Larry 纔是正確的。舉個反例說, 4 × 4 的矩陣,這兩個方案的 sum 不相等。
 (1)      2      3      4
  5       6     (7)     8
  9     (10)    11    12
 16     15     14   (13)
===================== sum1 = 31
 (1)      2      3      4
  5       6     (7)     8
  9      10     11   (12)
 16     (15)   14    13
===================== sum2 = 35
行向量 (16, 15, 14, 13) - ( 9, 10, 11, 12) = (7, 5, 3, 11) ,各分量不相等,在以 10 和 13 爲對角的子矩陣中, 不選取 10 和 13,改選取另外一組對角 12 和 15,那麼可以得到新的選取方案。
而 sum2 - sum1 = ( 12 + 15) - (10 + 13) = (15 - 10) - (13 - 12) = 4 。顯然,如果向量差的各分量都相等,那麼 sum 不變。那麼在生成全部方案的過程中,sum 一直保持不變。
因此只要判斷所有的行(列)向量兩兩之差的各分量都相等即可,但是這樣的時間複雜度是 O (row4) ,其實只要每個下標 1 <= i < row,  1 <= j <= col,四個元素滿足 (i, j) + (i + 1, j + 1) == (i + 1, j) + (i, j + 1) 這個條件即可,即每個“田”字的對角元素之和相等。這樣的時間複雜度是 O (row2) 。

例如這個矩陣就滿足這個條件,因此總是滿足 sum = 1 + 2 + 3 + 4 + 10 + 20 + 30 + 40 = 110 。
 11 12 13 14
 21 22 23 24
 31 32 33 34
 41 42 43 44

根據以上解法,就不難寫出代碼了^_^

#include <vector>
#include 
<list>
#include 
<map>
#include 
<set>
#include 
<deque>
#include 
<stack>
#include 
<bitset>
#include 
<algorithm>
#include 
<functional>
#include 
<numeric>
#include 
<utility>
#include 
<sstream>
#include 
<iostream>
#include 
<iomanip>
#include 
<cstdio>
#include 
<cmath>
#include 
<cstdlib>
#include 
<ctime>

using namespace std;

int entry [20] [20];
class SumOfSelectedCells {
public:
    
string hypothesis(vector <string>);
}
;

string SumOfSelectedCells::hypothesis(vector <string> table) {
    
int row = table.size ();
    
int i, j, col = 0;
    
string s;
    
for (i = 0; i < row; i ++)
    
{
        col 
= 0;
        stringstream ss(table [i]);
        
while (ss >> s)
        
{
            sscanf (s.c_str (), 
"%d"& entry [i] [col ++]);
        }

    }

    
if (row > col)    //  每一行必須都相等才能正確,否則存在某個被選位置,去掉它,在同一列裏選擇一個合適的位置,sum 變化
    {
        
for (i = 0; i < row - 1; i ++)
        
{
            
if (table [i] != table [i + 1])
            
{
                
return "INCORRECT";
            }

        }

        
return "CORRECT";
    }

    
if (row < col)    // 每一列必須都相等才能正確,否則存在某個被選位置,去掉它,在同一行裏選擇一個合適的位置,sum 變化
    {
        
for (j = 0; j < col - 1; j ++)
        
{
            
for (i = 0; i < col; i ++)
            
{
                
if (entry [i] [j] != entry [i] [j + 1])
                
{
                    
return "INCORRECT";
                }

            }

        }

        
return "CORRECT";
    }

    
// 行列數相等的時候,必須每個“田”字的兩組對角之和相等(即每兩個行向量,每兩個列向量之差的各分量相等)才能正確
    
// 否則存在兩個被選位置位於某個矩形的對角,去掉這兩個位置,選擇另外一組對角,sum 變化
    for (i = 0; i < row - 1; i ++)
    
{
        
for (j = 0; j < col - 1; j ++)
        
{
            
if (entry [i] [j] + entry [i + 1] [j + 1!= entry [i + 1] [j] + entry [i] [j + 1])
            
{
                
return "INCORRECT";
            }

        }

    }

    
return "CORRECT";
}


其中參數
vector <string> table 是字符串數組,先要從中讀取矩陣元素到二維數組 entry []  [] 中。
 

在 TC 的競賽客戶端 Arena 裏裝了個插件 KawigiEdit 2.0 ,會自動幫我生成預編譯指令,就是把那些頭文件都 include 進來了,還有類方法的聲明,以及測試代碼,以便本地測試。

另外,1000 分的那道題我用強力法加以優化(其實我覺得像是動態規劃),通過了系統測試,並沒有超時。最大的輸入是 1,000,000 ,而系統花了 800 ms 就搞定了(我的機子上要 1200 ms,比較慢^_^)。牛人們還沒有寫報告,所以我還沒有更好的辦法(例如搜索之類),期待 ing。。。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章