上午在打usaco月赛的铜组题,T1T2是用来秒杀的,然而T3卡了一上午,下面给出题面:
题意大概就是输入一个N*N的矩阵,矩阵中元素只有0与1两种状态,每次操作以左上角的点为矩阵中某一矩阵的左上方顶点,将该矩阵中所有元素状态改变(即0变为1,1变为0),求将矩阵中元素全部变为0的最小次数。
第一次看到样例的时候以为就是一道的DFS或BFS的搜索题,然后果断写了DFS,很正常就WA了。然而其实这道题需要用到贪心。。。
题目中提到,一个矩阵被改变两次之后还是原先的状态,那既然这样,如果将右下角的点留到最后处理的话,有很大可能会重复某次操作,所以每次操作的右下角顶点应该是从右下角开始搜索的,既然这样,每次操作的矩阵应该怎样选取呢?
因为最后要把所有的元素都变为0,那么最优解其实就是保证每次操作的右下角顶点都为1,并且保证该矩阵中所含1的个数最多。
那么这样的话策略就已经有了。代码如下:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<string> 5 #include<cstring> 6 using namespace std; 7 int sum[11][11],n,ans=0; 8 char a[11][11]; 9 string s[11]; 10 bool f[11][11]; 11 int main() 12 { 13 freopen("cowtip.in","r",stdin); 14 freopen("cowtip.out","w",stdout); 15 cin>>n; 16 for (int i=1;i<=n;i++) 17 cin>>s[i]; 18 for (int i=1;i<=n;i++) 19 for (int j=0;j<n;j++) 20 { 21 a[i][j+1]=s[i][j]; 22 f[i][j]=true; 23 sum[i][j+1]=sum[i-1][j+1]+sum[i][j]-sum[i-1][j]+a[i][j+1]-'0'; 24 } 25 for (;;) 26 { 27 bool flag=false; 28 for (int i=1;i<=n;i++) 29 { 30 for (int j=1;j<=n;j++) 31 if (a[i][j]=='1'){flag=true; break;} 32 if (flag) break; 33 } 34 if (!flag) break;//判断矩阵是否全部为0 35 ans++; 36 int maxx=0,x=0,y=0; 37 for (int i=1;i<=n;i++) 38 for (int j=1;j<=n;j++) 39 if (sum[i][j]>maxx&&a[i][j]=='1')//查找右下点状态为1且包含状态为1的元素的个数最多的矩阵的右下点 40 { 41 maxx=sum[i][j]; 42 x=i; y=j; 43 } 44 for (int i=1;i<=x;i++) 45 { 46 for (int j=1;j<=y;j++) 47 { 48 if (a[i][j]=='1') a[i][j]='0'; 49 else a[i][j]='1';//将所选取矩阵中所有元素的状态改变 50 } 51 } 52 for (int i=1;i<=n;i++) 53 for (int j=1;j<=n;j++) 54 sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j]-'0';//数据改变后再求矩阵前缀和 55 } 56 cout<<ans<<endl; 57 return 0; 58 }