题目大意:
有$n(nleq 13)$个人,其中你是1号.每个人都有一个初始经验值,给定一个$n*n$的矩阵gift,gift[i][j]表示第i个人与第j个人比赛能够获得的经验值.再给定一个$n*n$的矩阵val,val[i][j]表示第i个人与第j个人比赛获胜能赢得的积分(一个人获胜,当且仅的他当前的经验值大于其对手当前的经验值),两两进行一次比赛,请你安排顺序使你最后能赢得的总积分尽可能多,并输出最高能够获得的积分.
solution:
根据贪心策略,肯定先让自己与其他人比赛,这样才不会让其他人经验值增加太多.由于n比较小,所以考虑状压.又因为与其他人比赛无论输赢都能获得经验值,所以每个状态的经验值是固定的,预处理即可.接下来,便是愉快的收割题目时刻.
code:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #define R register #define next exnttttnext #define debug puts("MLG") #define mod 1234567891 using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; inline ll read(); inline void write(ll x); inline void writesp(ll x); inline void writeln(ll x); ll T,n; ll f[500000],Exp[500000],val[200][200],gift[200][200]; ll str[500]; ll tot,h[104]; inline void check(ll state,ll goal){ for(R ll i=state,now=0;i;i>>=1){ if(i&1) h[++tot]=now; ++now; } if(tot!=goal){ tot=0;return; } for(;tot;tot--){ f[state]=max(f[state],f[state-(1<<h[tot])]+(Exp[state-(1<<h[tot])]>str[h[tot]+1]?1:0)*val[0][h[tot]+1]); } } int main(){ T=read(); while(T--){ n=read(); memset(f,0,sizeof f); for(R ll i=0;i<n;i++){ for(R ll j=0;j<n;j++){ gift[i][j]=read(); } } for(R ll i=0;i<n;i++){ for(R ll j=0;j<n;j++){ val[i][j]=read(); } } for(R ll i=0;i<n;i++) str[i]=read(); for(R ll i=0;i<(1<<(n-1));i++){ Exp[i]=str[0]; for(R ll j=i,ToT=0;j;j>>=1){ if(j&1) Exp[i]+=gift[0][ToT+1]; ++ToT; } } for(R ll i=1;i<n;i++){ for(R ll j=0;j<(1<<(n-1));j++){ check(j,i); } } writeln(f[(1<<(n-1))-1]); } } inline ll read(){ ll x=0,t=1;char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') t=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x*t; } inline void write(ll x){ if(x<0){putchar('-');x=-x;} if(x<=9){putchar(x+'0');return;} write(x/10);putchar(x%10+'0'); } inline void writesp(ll x){ write(x);putchar(' '); } inline void writeln(ll x){ write(x);putchar(' '); }