问题 B: 导游2
时间限制: 1 Sec 内存限制: 128 MB提交: 84 解决: 52
[提交][状态][讨论版]
题目描述
宁波市的中小学生们在镇海中学参加程序设计比赛之余,热情的主办方邀请同学们参观镇海中学内的各处景点,已知镇海中学内共有n处景点。现在有n位该校的学生志愿承担导游和讲解任务。每个学生志愿者对各个景点的熟悉程度是不同的,如何将n位导游分配至n处景点,使得总的熟悉程度最大呢?要求每个景点处都有一个学生导游。
输入
有若干行:
第一行只有一个正整数n,表示有n个景点和n个学生导游。
第二行至第n+1行共n行,每行有n个以空格分隔的正整数。第i+1行的第j个数k(1≤k≤1000),表示第i个学生导游对景点j的熟悉程度为k。
输出
只有一行,该行只有一个正整数,表示求得的熟悉程度之和的最大值。
样例输入
3 10 6 8 9 2 3 1 7 2
样例输出
24
提示
【样例说明】
第 10.5pt">1个学生负责第3个景点,第 10.5pt">2个学生负责第1个景点,第 10.5pt">3个学生负责第2个景点时,熟悉程度总和为24,达到最大值。 10.5pt">
【数据限制】
100%的数据,1≤n≤17。
如果熟悉dp的大牛应该不难发现这也是一道状态压缩类的dp,压缩什么状态呢,当然是n,数据范围小,可以用1表示哪个景点已经有人了,0表示还没有人。这样一个转移思路就出来了,用记忆化实现,一个状态中比如1000011100 枚举每一个二进制位为1,表示第4个学生去哪个景点,这样每次转移,复杂度为O(n*(1<<n)) 大约10 million 左右

#include<cstdio> #include<algorithm> #include<cmath> #include<iostream> #include<cstring> #include<string> using namespace std; const int MAXN=19; int a[MAXN][MAXN],dp[(1<<17)+7]; int n; void init() { memset(dp,-1,sizeof(dp)); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) scanf("%d",&a[i][j]); } void dfs(int sta,int num) { if (num==0) { dp[sta]=0; return; } if (dp[sta]!=-1) return; int res=0; for (int i=0;i<n;i++) { int x=sta; if ((1<<i)&sta) { x=x^(1<<i); dfs(x,num-1); res=max(res,dp[x]+a[num][i+1]); } } dp[sta]=res; } int main() { scanf("%d",&n); init(); dfs((1<<n)-1,n); printf("%d",dp[((1<<n)-1)]); }