2024年GPLT團體程式設計比賽L2-D吉利矩陣題解

游辰發表於2024-04-21

只能說比賽時前期做得太慢了,後面導致題目只能撈點分數(IOI賽制),當時這道題是我不剪枝DFS拿了4分,壓線拿銅牌!
考完試一做,發現是個大水題(bushi)
主要原理:DFS(深度優先搜尋) + 剪枝
名言:學搜尋核心就是學剪枝
廢話不說了,見程式碼

點選檢視程式碼
//原理:DFS + 剪枝
#include <bits/stdc++.h>
using namespace std;
int k,n;//k為要求的行列和,n為方格大小
int row[5];//row為已經填好數的某行的和
int col[5];//col同理
//神之一筆:剪枝.(1)如果n-1定了,最後一個不用管了,一定為k - row[x](列同理).(2)列舉可填數的時候可以限定範圍,維護行列和不超過k
int ans;//記錄答案
void DFS(int x,int y)//核心DFS
{
    if(y > n-1)//如果要換行了
    {
        x++;//換行
        y = 1;//重置y
    }
    if(x == n)//如果到了底行,進行特判(之前的行列和(左上角的n-1矩陣)滿足<=k,但是不能保證最後的行列和<=k,故要特判)
    {
        //其實由數學推算:最後右下角的代表數是一致的,故sumr與sumc一個就夠了,沒觀察出也沒關係,兩個不影響
        int sumr = 0,sumc = 0;//初始化為0
        for (int i = 1;i<=n-1;i++) sumc += (k - row[i]);//累加之前行
        for (int i = 1;i<=n-1;i++) sumr += (k - col[i]);//累加之前列
        if(sumc <= k&&sumr <= k) ans++;//如果<=k,答案合法,+1
        return;//切記,一定要返回
    }
    for (int i = 0;i<=k-row[x]&&i<=k-col[y];i++)//限制性列舉,維護左上角矩陣行列和<=k,記住從0開始
    {
        row[x] += i;//累加行
        col[y] += i;//累加列
        DFS(x,y+1);//遞迴搜尋
        row[x] -= i;//刪去
        col[y] -= i;//刪去
    }
}
int main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>k>>n;//輸入
    DFS(1,1);//搜尋
    cout<<ans<<"\n";//輸出
    return 0;
}


好了,其實就是這麼簡單(bushi),這道題確實是練搜尋剪枝的好題

相關文章