导游
宁波市的中小学生们在镇海中学参加程序设计比赛之余,热情的主办方邀请同学们参观镇海中学内的各处景点,已知镇海中学内共有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算法