洛谷p2258 子矩陣

2022-02-19 20:25:33 字數 2661 閱讀 9829

子矩陣【題目鏈結】

然後這是一道非常暴力的題,首先是直接dfs的暴力操作:

因為同時枚舉行和列不好列舉,所以我們可以先枚舉行,當行列舉完了,再列舉列。然後都列舉完了,就可以按照題目要求算一下,然後比較算到的答案與當前值的大小,保留較小的那乙個。

code:

#includeusing

namespace

std;

int n,m,r,c,ans=0x7ffffff

;int map[17][17],dp2[17],dp1[17

];void

dp()

void dfs(int x,int y,int nr,int

nc)

if(nr==r+1

)

return

; }

else

for(int i=x;i<=n;i++)

}int

main()

親測不加-o2 55pts,加了-o2 70pts;

然後是正解。

#define ych 預處理

正解也是很神奇的,他不是乙個簡單地dp,而是建立在搜尋上的dp!?

首先我們還是搜尋,這次只搜尋行,然後當搜尋了r行之後,對列進行dp。

搜尋:

void dfs(int x,int

nr)}

dp1[i]記錄列舉的邊的編號;

x記錄當前已經列舉到的邊,nr記錄選擇了幾條邊;

首先幾個定義的陣列:

ver[i],定義的前提是你已經列舉好行了(分別記為k1,k2,……,kr),然後表示的是:第i列的列舉的每相鄰的兩行的差的絕對值的和。

emm有點亂,然後我們舉個例子:

假設我們列舉的行是:k1,k2,k3……kr,然後我們用map[i][j]存第i行第j列的值;

然後ver[i]=abs(map[k2][i]-map[k1][i])+abs(map[k3][i]-map[k2][i])+……+abs(map[kr][i]-map[kr-1][i])

對應到**裡就是:

for(int i=1;i<=m;i++)

for(int j=2;j<=r;j++)

ver[i]+=abs(map[dp1[j]][i]-map[dp1[j-1]][i]);

del[i][k],定義前提與ver相同,然後表示的是:第i列和第k列左右差的和,然後還是很抽象對吧:

再舉個例子:

假設我們列舉的行是:k1,k2,k3……kr,然後我們用map[i][j]存第i行第j列的值;

然後del[i][k]=abs(map[k1][i]-map[k1][k])+abs(map[k2][i]-map[k2][k])+……+abs(map[kr][i]-map[kr][k]);

對應到**裡:

for(int i=1;i<=m;i++)//

列舉是哪一列

for(int k=i+1;k<=m;k++)//

列舉另一列

for(int j=1;j<=r;j++)//

枚舉行 del[i][k]+=abs(map[dp1[j]][k]-map[dp1[j]][i]);

然後是ych:

對於只選一列的情況,顯然它的值就等於所選那一列的ver(沒有左右可以減所以莫得del的事情);

for(int i=1;i<=m;i++)

f[i][

1]=ver[i];

然後是dp正解部分:

定義f[i][j]表示在前i條邊中選擇j條邊並且恰好選擇了第i條邊的最小分值(哦對了別忘記初始化f為乙個很大的數),那麼轉移方程就是:f[i][j]=min(f[i][j],f[i-k][j-1]+ver[i]+del[i-k][i]);

大概是可以理解的吧?解釋一下:

f[i-k][j-1]+ver[i]+del[i-k][i]:從第i-k列選擇j-1條邊,然後再選擇第i條邊(選擇以後與i相鄰的就是i-k這一列,那麼需要加的代價就是第i列的ver,以及第i列和第i-k列的del);

然後**實現:

for(int i=1;i<=m;i++)

for(int j=1;j<=c;j++)

for(int k=1;k=j-1;k++)

f[i][j]=min(f[i][j], f[i-k][j-1]+ver[i]+del[i-k][i]);

這裡的k要保證i-k≥j-1,原因是f[i-k][j-1]表示的是從前i-k列中選擇j-1列,如果i-k最後列舉最小的:

for(int i=c;i<=m;i++)//

從c開始列舉也是因為樓上i-k與j-1的關係的原因

ans=min(ans,f[i][c]);

code:

#includeusing

namespace

std;

int n,m,r,c,ans=0x7ffffff

;int map[17][17],dp1[17],ver[17],del[17][17],f[17][17

];void

dp()

void dfs(int x,int

nr)}

intmain()

end-

洛谷P2258 子矩陣

題目 如果暴力的話,時間複雜度是 rcc n,n 2 2 主要考察搜尋枚舉行和列,並沒有用到dp的思想。考慮優化的話,發現枚舉行或列中至少需要一步,因為這個題只能預處理優化,如果都不列舉,就相當於盲人摸象,無法預處理來優化。因此要搜尋枚舉行或列,然後預處理並在列或行上跑dp,這樣就可以少些列舉時間,...

洛谷P2258 子矩陣

給出如下定義 子矩陣 從乙個矩陣當中選取某些行和某些列交叉位置所組成的新矩陣 保持行與列的相對順序 被稱為原矩陣的乙個子矩陣。例如,下面左圖中選取第2 4行和第2 4 5列交叉位置的元素得到乙個2 3的子矩陣如右圖所示。9 3 3 3 9 9 4 8 7 4 1 7 4 6 6 6 8 5 6 9 ...

洛谷 P2258 子矩陣

給出如下定義 子矩陣 從乙個矩陣當中選取某些行和某些列交叉位置所組成的新矩陣 保持行與列的相對順序 被稱為原矩陣的乙個子矩陣。例如,下面左圖中選取第22 44行和第22 44 55列交叉位置的元素得到乙個2 times 32 3的子矩陣如右圖所示。9 3 3 3 9 9 4 8 7 4 1 7 4 ...