1. 程式人生 > >藍橋杯 剪格子

藍橋杯 剪格子

問題描述
如下圖所示,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;
}