[20200720NOIP提高组模拟T4]五子棋

题目大意:

  有$n(n\leq 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('\n');
}

 

posted @ 2020-07-20 20:17  月落乌啼算钱  阅读(162)  评论(0编辑  收藏  举报