子矩陣【題目鏈結】
然後這是一道非常暴力的題,首先是直接dfs的暴力操作:
因為同時枚舉行和列不好列舉,所以我們可以先枚舉行,當行列舉完了,再列舉列。然後都列舉完了,就可以按照題目要求算一下,然後比較算到的答案與當前值的大小,保留較小的那乙個。
code:
#includeusingnamespace
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,intnr)}
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:
#includeusingnamespace
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 ...