导游

 

宁波市的中小学生们在镇海中学参加程序设计比赛之余,热情的主办方邀请同学们参观镇海中学内的各处景点,已知镇海中学内共有n处景点。现在有n位该校的学生志愿承担导游和讲解任务。每个学生志愿者对各个景点的熟悉程度是不同的,如何将n位导游分配至n处景点,使得总的熟悉程度最大呢?要求每个景点处都有一个学生导游。

输入
输入文件daoyou.in中有若干行:

第一行只有一个正整数n,表示有n个景点和n个学生导游。

第二行至第n+1行共n行,每行有n个以空格分隔的正整数。第i+1行的第j个数k(1≤k≤1000),表示第i个学生导游对景点j的熟悉程度为k。

输出
输出文件daoyou.out只有一行,该行只有一个正整数,表示求得的熟悉程度之和的最大值。

样例输入
3 10 6 8 9 2 3 1 7 2

样例输出
24

数据范围
50%的数据,1≤n≤9。

100%的数据,1≤n≤17。

纯粹的暴力,过不了的

#include <bits/stdc++.h>
using namespace std;
 
struct stu
{
    int a[20];
}s[20];
 
int n,maximum = 0;
bool vis[20] = {false};
 
void dfs(int depth, int sum){
    if(depth >= n){
        if(sum > maximum)
            maximum = sum;
        return;
    }
 
    for (int i = 0; i < n; ++i)
    {
        if(!vis[i]){
            vis[i] = true;
            dfs(depth+1, sum + s[i].a[depth]);
            vis[i] = false;
        }
    }
}
 
int main()
{
    scanf("%d",&n);
    for (int i = 0; i < n; ++i){
        for (int j = 0; j < n; ++j){
            scanf("%d",&s[i].a[j]);
        }
    }
 
    dfs(0,0);
    printf("%d\n", maximum);
 
    return 0;
}

  加下剪枝

#include <bits/stdc++.h>
using namespace std;
  
int n;
int s[20];
int a[20][20];
int vis[20];
int ans;
  
void dfs(int step, int sum){
    if(step == n){
        ans = max(ans,sum);
        return;
    }
    if(sum + s[step] <= ans)
        return;
    for (int i = 0; i < n; ++i) 
	{
        if(!vis[i]) 
		{
            vis[i] = 1;
            dfs(step + 1, sum + a[step][i]);
            vis[i] = 0;
        }
    }
}
  
int main()
{
    cin >> n;
    
    for (int i = 0; i < n; ++i) 
	{
		int m = 0;
        for (int j = 0; j < n; ++j) 
		{
            cin >> a[i][j];
            m = max(m,a[i][j]); //取出每一行的最大值 
        }
        s[i] = m;
    }
    for (int i = n-1; i >= 0; --i) 
	{
        s[i] += s[i+1];
        //s[i]代表从第i行到第N行,每行取最大值时,可以取到的最优值 
    }
    dfs(0,0);
    cout << ans << endl;
  
    return 0;
}

  

 

  正解为状态压缩DP.时间复杂度为O(N*2^N)

#include <bits/stdc++.h>
using namespace std;
int n,a[20][20],f[20][250000];
int main()
{
    scanf("%d",&n);
    for (int i=1; i<=n; i++)         
    for (int j=1; j<=n; j++)      
    scanf("%d",&a[i][j]);
    memset(f,128,sizeof(f));
    f[0][0]=0;
    for (int i=1; i<=n; i++)         
    for (int j=0; j<=(1<<n)-1; j++)         
    if (f[i-1][j]>=0)         
    {
                for (int x=0; x<=n-1; x++)             
                if (((1<<x)&j)==0)              
                f[i][j|(1<<x)]=max(f[i][j|(1<<x)],f[i-1][j]+a[i][x+1]);
    }
    printf("%d\n",f[n][(1<<n)-1]);
    return 0;
}
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
 
const int maxn=17;
int a[maxn+1][maxn+1];
int dp[1<<maxn];
int n,num;
 
int main()
{
	cin>>n;
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
			cin>>a[i][j];
	memset(dp,0,sizeof(dp));
	for (int sta=1;sta<=(1<<n)-1;sta++)
	{
		num=0;
		for (int j=0;j<n;j++)
			if ((sta&(1<<j))>0) num++;
		for (int i=1;i<=n;i++)
			if (sta&(1<<(i-1)))
				dp[sta]=max(dp[sta],dp[sta-(sta&(1<<(i-1)))]+a[num][i]);
	}
	cout<<dp[(1<<n)-1];	
	return 0;
}

  

  

有兴趣的可以写下KM算法

posted @ 2020-08-21 23:30  我微笑不代表我快乐  阅读(115)  评论(0编辑  收藏  举报