题目背景
XM大战
如期而至,Agent
们齐聚一地,展开最后的对决。对战有很多种方式,有些复杂的方式可以获得更高的分数。可惜ENLIGHTENED
的人并不怎么聪明,只会简单的hack
,所以ENLIGHTENED行动指挥
找到了你来做他们的总参谋。
题目描述
地图上有NN个Portal
,现在某一名Agent
的任务是占领该地图上的MM个Portal
,这名Agent
占领第ii个Portal
可以得到的分数为A[i]A[i],除了直接占领,还有其他的KK种加分方式,对于着NN个Portal
,在占领完第X[i]X[i]个Portal
后占领第Y[i]Y[i]个Portal
可以获得B[i]B[i]的加分,加分可能会有重复。Agent
希望他可以为团队争取更多的分数,所以请求作为大战参谋的你来帮助他。
输入输出格式
输入格式:
第一行是输入三个整数N,M,KN,M,K 第二行输入是NN个数,第ii个数代表A[i]A[i]的值。 下面KK行每行有3个整数X[i],Y[i],C[i]X[i],Y[i],C[i],表示在占领完第X[i]X[i]个Portal
后占领第Y[i]Y[i]个Portal
可以获得B[i]B[i]的加分
输出格式:
输出仅一行一个整数,为该名Agent
可以获得的最大分数值。
输入输出样例
输入样例#1: 复制
3 2 1 1 1 1 1 2 3
输出样例#1: 复制
5
输入样例#2: 复制
4 3 2 1 1 1 1 4 3 2 3 2 1
输出样例#2: 复制
6
说明
对于20\%20%的数据 1 \leq M \leq N \leq 4,0 \leq A[i],B[i] \leq 10^31≤M≤N≤4,0≤A[i],B[i]≤103
对于40\%40%的数据 1 \leq M \leq N \leq 8,0 \leq A[i],B[i] \leq 10^51≤M≤N≤8,0≤A[i],B[i]≤105
对于60\%60%的数据 1 \leq M \leq N \leq 12,0 \leq A[i],B[i] \leq 10^71≤M≤N≤12,0≤A[i],B[i]≤107
对于100\%100%的数据 $1 \leq M,X[i],Y[i] \leq N \leq 18,0 \leq K \leq N^2−N,0 \leq A[i],B[i] \leq 10^9$
我们DP
数组,用状态压缩,代表有那些点已经被占领过了,代表上一次我占的是那个。对于每一次状态转移,若当前我们要占领的Portal
在占领后有加分,那么就转移加分与基础值的和,否则只转移基础值。最后判断一下当代表的状态已经有占领个了,就记录下当前的最大值。
#include<bits/stdc++.h>
#define f(i,l,r) for(i=(l);i<=(r);i++)
using namespace std;
const int MAXN=19;
int n,m,K;
long long ans;
long long f[1<<19][MAXN],a[MAXN],b[MAXN][MAXN];
int main()
{
ios::sync_with_stdio(false);
int i,j,k,x,y,w,num=0;
cin>>n>>m>>K;
f(i,0,n-1){
cin>>a[i];
}
f(i,1,K){
cin>>x>>y>>w;
if(x==y) a[i]+=w;
else b[x-1][y-1]+=w;
}
f(i,0,n-1){
f[1<<i][i]=a[i];
}
f(i,1,(1<<n)-1){
num=0;
f(j,0,n-1){
if(!(i&(1<<j))) continue;
num++;
f(k,0,n-1){
if(!(i&(1<<k))) continue;
if(k==j) continue;
f[i][j]=max(f[i][j],f[i^(1<<j)][k]+a[j]+b[k][j]);
}
}
if(num==m){
f(j,0,n-1){
if(!(i&(1<<j))) continue;
ans=max(ans,f[i][j]);
}
}
}
cout<<ans<<endl;
return 0;
}