【编程之美资格赛】题目3 : 格格取数

本文探讨了一种针对矩阵寻找最优子矩阵求和的问题。通过深度优先搜索(DFS)和广度优先搜索(BFS)两种方法进行了实现,并对比了不同情况下的效率。最终给出了一个更优的解决方案。
自己以为是类似八皇后之类的,然后写了个搜索,结果wa了,一直找不到错,直到
神奇的数据测试,

1  100 100

1  100 100

100 1   1

Solution是1+1+1+1 = 4,但是该矩阵的子矩阵

100 100

 1    1

的Solution是 100+1 = 101

自己的代码:
#include <stdio.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <iostream>
#include<cmath>
using namespace std;
int a[105][105],minal=2*1000000,m,n,vis[105],map[105][105],minal_ans;
void dfs(int cur,int ans)
{
    int i,tmp=0,j,k,q;
    if(cur==m)
    {
        for(i=1; i<=n; i++)
        {
            tmp=0;
            if(!vis[i])
            {
                tmp=ans+a[m][i];
                if(m==n)
                {
                    if(tmp<minal_ans)
                    minal_ans=tmp;
                    return;
                }
                vis[i]=1;
                for(j=1; j<=n; j++)
                {
                    int n_min=1000005;
                    if(!vis[j])
                    {
                        for(k=1; k<=m; k++)
                            if(a[k][j]<n_min)
                                n_min=a[k][j];
                        tmp+=n_min;
                    }

                }
                vis[i]=0;
                if(minal_ans>tmp)
                    minal_ans=tmp;
            }

        }
    }
    else
        for(i=1; i<=n; i++)
        {
            if(!vis[i])
            {
                vis[i]=1;
                map[cur][i]=1;
                dfs(cur+1,ans+a[cur][i]);
                vis[i]=0;
                map[cur][i]=0;
            }
        }
}
void bfs(int cur,int ans)
{
    int i,tmp=0,j,k,q;
    if(cur==n)
    {
        for(i=1; i<=m; i++)
        {
            tmp=0;
            if(!vis[i])
            {
                tmp=ans+a[i][n];
                minal=tmp;
                vis[i]=1;
                for(j=1; j<=m; j++)
                {
                    int n_min=1000005;
                    if(!vis[j])
                    {
                        for(k=1; k<=n; k++)
                            if(a[j][k]<n_min)
                                n_min=a[j][k];
                        tmp+=n_min;
                    }
                }
                vis[i]=0;
                if(minal_ans>tmp)
                {
                    minal_ans=tmp;
                }
            }
        }
    }
else
    for(i=1; i<=m; i++)
    {
        if(!vis[i])
        {
            vis[i]=1;
            bfs(cur+1,ans+a[i][cur]);
            vis[i]=0;
        }
    }

}
int main()
{
    int t,i,j,tt=1;
    //freopen("in.txt","r",stdin);
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&m,&n);
        for(i=1; i<=m; i++)
            for(j=1; j<=n; j++)
            {
                scanf("%d",&a[i][j]);
            }
        minal_ans=2*1000000;;
        if(m<=n)
        {
            memset(vis,0,sizeof(vis));
            dfs(1,0);
        }
        else
        {
            memset(vis,0,sizeof(vis));
            bfs(1,0);
        }
        printf("Case %d: %d\n",tt++,minal_ans);
    }
    return 0;
}



正确的同侪的代码:
#include<stdio.h>
#include<string.h>
int r[6],c[6];
int n,m,res;
int mp[6][6];
void dfs(int min) {
	int i,j,flg=0;
	if(min>=res) return ;
	for(i=0;i<n;i++){
		if(!r[i]){
			flg=1;break;
		}
	}
	for(i=0;i<m;i++){
		if(!c[i]) {
			flg=1;break;
		}
	}
	if(!flg) {
		if(min<res)
			res=min;
		return ;
	}
	for(i=0;i<n;i++) {
		for(j=0;j<m;j++) {
			int x=1,y=1;
			if(!r[i]||!c[j]) {
				if(!r[i]) x=0;
				if(!c[j]) y=0;
				r[i]=1,c[j]=1;
				dfs(min+mp[i][j]);
				if(!x) r[i]=0;
				if(!y) c[j]=0;
			}
		}
	}
	return ;
}
void init() {
	memset(r,0,sizeof(r));
	memset(c,0,sizeof(c));
}
int main() {
	int t,o=1;
	scanf("%d",&t);
	while(t--) {
		init();
		scanf("%d%d",&n,&m);
		int i,j,k;
		for(i=0;i<n;i++){
			for(j=0;j<m;j++) {
				scanf("%d",&mp[i][j]);
			}
		}
		res=999999;
		dfs(0);
		printf("Case %d: %d\n",o++,res);
	}
}



                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值