开公司(排列枚举、DFS)

题目描述

Feynman有一天开了自己的公司,现在他有n件事情待解决,他手下恰好有n人。于是Feynman想要将这n件事分给n个人去做。已知每个人都可以做每件事,但是每个人做每件事的效率不同。下面给出每件事不同人做所需时间,请帮Feynman挑选合适的人去做事,使得总时间最短。


输入格式

第一行输入一个整数N,代表有N个员工,员工编号从1到N。(1<=N<=10)

接着输入一个N*N的二维矩阵,task[N][N],task[i][j]指的是第i项工作如果由j号员工完成所需的时间。、

0<=task[i][j]<=1000


输出格式

输出结果包含一个整数,代表所需要的最短时间(求和)。


样例输入
6
10 11 12 11 9 11
11 9 10 13 11 12
12 10 11 10 13 9
9 14 9 10 10 11
10 10 9 11 12 11
10 7 10 10 10 8
样例输出
54


思路1

递归思想(类似N皇后,不用判断对角线)因为一个任务对应一个人,所以每一行(一个任务)只能选择一个人(对应列)

对行进行dfs,每一列进行循环枚举,进入的对列进行标记,后面不能使用,sum增加;出来后清楚标记,sum减小。

边界条件即为l等于n,遴选最小的sum。


代码示例1

#include<iostream>
using namespace std;

int map[10][10];
int hang[10];
int lie[10];
int n,sum;
int Min=0xfffffff;

void dfs(int l)
{
	if(l==n){
		//cout<<sum<<"...."<<endl;
		if(sum<Min) Min=sum;
		return ;
	}
	for(int i=0;i<n;++i){
		if(lie[i]==0){
			sum+=map[l][i];
			lie[i]=1;
			dfs(l+1);
			sum-=map[l][i];
			lie[i]=0;
		}
	}
}

int main()
{
	cin>>n;
	for(int i=0;i<n;++i){
		for(int j=0;j<n;++j){
			cin>>map[i][j];
		}
	}
	dfs(0);
	cout<<Min<<endl;
	return 0;
}

思路2

因为一个任务只能选择一个人,一个人不同重复做事,所以可以对于每个人做的事进行全排列,最后取最小值(和思路1的根源实际上是一样的,直接调用stl中的next_permutation)

可以用一个数组保存每项工作由几号员工完成,初始的化成{1, 2, 3, ... n},对于这个数组全排列枚举即可。


代码示例2

#include<iostream>
#include<algorithm>
using namespace std;

int map[10][10];
int arr[10];//全排列枚举

int main()
{
	int n;
	cin>>n;
	for(int i=0;i<n;++i){
		for(int j=0;j<n;++j){
			cin>>map[i][j];
		}
	}
	for(int i=0;i<n;++i) arr[i]=i;
	int Min=0xfffff;
	int sum;
	do{
		sum=0;
		for(int i=0;i<n;++i){
			sum+=map[i][arr[i]];
		}
		//cout<<sum<<"sf"<<endl;
		if(sum<Min) Min=sum;
	}while(next_permutation(arr,arr+n));
	cout<<Min<<endl;
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值