藍橋杯 剪格子
阿新 • • 發佈:2019-02-15
問題描述 如下圖所示,3 x 3 的格子中填寫了一些整數。 +--*--+--+ |10* 1|52| +--****--+ |20|30* 1| *******--+ | 1| 2| 3| +--+--+--+ 我們沿著圖中的星號線剪開,得到兩個部分,每個部分的數字和都是60。 本題的要求就是請你程式設計判定:對給定的m x n 的格子中的整數,是否可以分割為兩個部分,使得這兩個區域的數字和相等。 如果存在多種解答,請輸出包含左上角格子的那個區域包含的格子的最小數目。 如果無法分割,則輸出 0。 輸入格式 程式先讀入兩個整數 m n 用空格分割 (m,n<10)。 表示表格的寬度和高度。 接下來是n行,每行m個正整數,用空格分開。每個整數不大於10000。 輸出格式 輸出一個整數,表示在所有解中,包含左上角的分割區可能包含的最小的格子數目。 樣例輸入1 3 3 10 1 52 20 30 1 1 2 3 樣例輸出1 3 樣例輸入2 4 3 1 1 1 1 1 30 80 2 1 1 1 100 樣例輸出2 10
#include<iostream> #include<cstring> using namespace std; int number_rest,m,n,ans,SUM,mat[10][10],used[10][10],vis[10][10],dir[4][2]={{-1, 0}, {1, 0}, {0, 1}, {0, -1}}; void dfs_rest(int x,int y) { vis[x][y]=1; number_rest++;//累加未選中的格子 for(int i=0;i<4;i++) { int nx=dir[i][0]+x; int ny=dir[i][1]+y; if(nx >= 1 && nx <= n && ny >= 1 && ny <= m && !used[nx][ny]&&!vis[nx][ny]) dfs_rest(nx,ny); } } void dfs_use(int x, int y,int number,int sum) { if(sum>SUM/2) return; if(sum==SUM/2) { memset(vis,0,sizeof(vis)); int i,j,ok=0; for(i=1;i<=n;i++) { for(j=1;j<=m;j++) if(!used[i][j]) { ok=1; break;} if(ok) break; } number_rest=0; dfs_rest(i,j); if(number+number_rest==n*m) ans=min(ans,number); return; } for(int i=0;i<4;i++) { int nx = x + dir[i][0], ny = y + dir[i][1]; if(nx >= 1 && nx <= n && ny >= 1 && ny <= m && !used[nx][ny]) { used[nx][ny] = true; sum += mat[nx][ny]; number=number+1; dfs_use(nx, ny,number, sum); used[nx][ny] = false; //回溯,恢復原來狀態 sum -= mat[nx][ny]; number=number-1; } } } int main() { cin>>m>>n; ans = 0xFFFF; for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) cin >> mat[i][j],SUM+=mat[i][j]; used[1][1]=true; if(SUM%2) cout<<0<<endl; else dfs_use(1, 1,1, mat[1][1]), cout<< (ans!=0xFFFF ? ans : 0)<<endl; return 0; }
感謝@Vascal的提醒,原程式存在問題,只能搜尋一筆畫的路徑,像T字型,十字型的路徑無法搜尋,因此重寫了程式碼,新程式碼可讀性差了點,稍微做了點備註,希望各位能讀懂。
#include<iostream> #include<cstring> using namespace std; int number_rest,m,n,ans,SUM,mat[10][10],used[10][10],vis[10][10],dir[4][2]={{-1, 0}, {1, 0}, {0, 1}, {0, -1}}; void dfs_rest(int x,int y) { vis[x][y]=1; number_rest++; for(int i=0;i<4;i++) { int nx=dir[i][0]+x; int ny=dir[i][1]+y; if(nx >= 1 && nx <= n && ny >= 1 && ny <= m && !used[nx][ny]&&!vis[nx][ny]) dfs_rest(nx,ny); } } void dfs(int x, int y,int sum,int num) { if(sum>SUM/2) return; if(sum==SUM/2) { memset(vis,0,sizeof(vis)); int i,j,ok=0; for(i=1;i<=n;i++) { for(j=1;j<=m;j++) if(!used[i][j]) { ok=1; break;} if(ok) break; } number_rest=0; dfs_rest(i,j); if(num+number_rest==n*m) ans=min(ans,num); /* ************************除錯程式碼****************************** for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) if(used[i][j]) cout<<mat[i][j]<<" "; else cout<<0<<" "; cout<<endl; } ***************************************************************/ return; } int p[3],c=0; for(int i=0;i<4;i++) { int nx = x + dir[i][0], ny = y + dir[i][1]; if(nx >= 1 && nx <= n && ny >= 1 && ny <= m && !used[nx][ny]) p[c++]=i; } /*****************搜尋一個點之後回溯 ,一筆畫的搜尋路徑 ********************/ // for(int i=0;i<c;i++) { int nx = x + dir[p[i]][0], ny = y + dir[p[i]][1]; used[nx][ny] = true; dfs(nx, ny, sum+mat[nx][ny],num+1); used[nx][ny] = false; } /***************************************************************************/ /************************T字型搜尋路徑,搜尋之後回溯***********************/ if(c==2) { used[x+dir[p[0]][0]][y + dir[p[0]][1]]=1; used[x+dir[p[1]][0]][y + dir[p[1]][1]]=1; dfs(x+dir[p[0]][0],y+dir[p[0]][1],sum+mat[x+dir[p[0]][0]][y+dir[p[0]][1]]+mat[x+dir[p[1]][0]][y+dir[p[1]][1]],num+2); dfs(x+dir[p[1]][0],y+dir[p[1]][1],sum+mat[x+dir[p[0]][0]][y+dir[p[0]][1]]+mat[x+dir[p[1]][0]][y+dir[p[1]][1]],num+2); used[x+dir[p[0]][0]][y + dir[p[0]][1]]=0;// used[x+dir[p[1]][0]][y + dir[p[1]][1]]=0;// } /*************************************************************************/ if(c==3) { /********************十字型搜尋路徑***************************/ used[x+dir[p[0]][0]][y + dir[p[0]][1]]=1; used[x+dir[p[1]][0]][y + dir[p[1]][1]]=1; used[x+dir[p[2]][0]][y + dir[p[2]][1]]=1; dfs(x+dir[p[0]][0],y+dir[p[0]][1],sum+mat[x+dir[p[0]][0]][y+dir[p[0]][1]]+mat[x+dir[p[1]][0]][y+dir[p[1]][1]]+mat[x+dir[p[2]][0]][y + dir[p[2]][1]],num+3); dfs(x+dir[p[1]][0],y+dir[p[1]][1],sum+mat[x+dir[p[0]][0]][y+dir[p[0]][1]]+mat[x+dir[p[1]][0]][y+dir[p[1]][1]]+mat[x+dir[p[2]][0]][y + dir[p[2]][1]],num+3); dfs(x+dir[p[2]][0],y+dir[p[2]][1],sum+mat[x+dir[p[0]][0]][y+dir[p[0]][1]]+mat[x+dir[p[1]][0]][y+dir[p[1]][1]]+mat[x+dir[p[2]][0]][y + dir[p[2]][1]],num+3); /************************************************************/ /******************T字型搜尋路徑*****************************/ used[x+dir[p[0]][0]][y + dir[p[0]][1]]=0; dfs(x+dir[p[2]][0],y+dir[p[2]][1],sum+mat[x+dir[p[1]][0]][y+dir[p[1]][1]]+mat[x+dir[p[2]][0]][y + dir[p[2]][1]],num+2); dfs(x+dir[p[1]][0],y+dir[p[1]][1],sum+mat[x+dir[p[1]][0]][y+dir[p[1]][1]]+mat[x+dir[p[2]][0]][y + dir[p[2]][1]],num+2); used[x+dir[p[0]][0]][y + dir[p[0]][1]]=1; used[x+dir[p[1]][0]][y + dir[p[1]][1]]=0; dfs(x+dir[p[2]][0],y+dir[p[2]][1],sum+mat[x+dir[p[0]][0]][y+dir[p[0]][1]]+mat[x+dir[p[2]][0]][y + dir[p[2]][1]],num+2); dfs(x+dir[p[0]][0],y+dir[p[0]][1],sum+mat[x+dir[p[0]][0]][y+dir[p[0]][1]]+mat[x+dir[p[2]][0]][y + dir[p[2]][1]],num+2); used[x+dir[p[2]][0]][y + dir[p[2]][1]]=0; used[x+dir[p[1]][0]][y + dir[p[1]][1]]=1; dfs(x+dir[p[1]][0],y+dir[p[1]][1],sum+mat[x+dir[p[0]][0]][y+dir[p[0]][1]]+mat[x+dir[p[1]][0]][y + dir[p[1]][1]],num+2); dfs(x+dir[p[0]][0],y+dir[p[0]][1],sum+mat[x+dir[p[0]][0]][y+dir[p[0]][1]]+mat[x+dir[p[1]][0]][y + dir[p[1]][1]],num+2); used[x+dir[p[1]][0]][y + dir[p[1]][1]]=0; used[x+dir[p[0]][0]][y + dir[p[0]][1]]=0; /**********************************************************/ } } int main() { cin>>m>>n; ans = 0xFFFF; for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) cin >> mat[i][j],SUM+=mat[i][j]; used[1][1]=true; if(SUM%2) cout<<0<<endl; else dfs(1, 1, mat[1][1],1), cout<< (ans!=0xFFFF ? ans : 0)<<endl; return 0; }