Hiho coder: #1200 : Increase Charisma Points

39 篇文章 0 订阅
35 篇文章 0 订阅
<span style="font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 17.7778px; line-height: 25.3968px; background-color: rgb(255, 255, 255);">时间限制:</span><span style="font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 17.7778px; line-height: 25.3968px; box-sizing: border-box; margin-left: 10px; background-color: rgb(255, 255, 255);">10000ms</span>
单点时限: 1000ms
内存限制: 256MB

描述

Little Ho is playing a role-playing game. There are N cities in the game which are numbered from 1 to N. Every time Little Ho moves to another city his charisma (a kind of character attribute) will increase by 1 point no matter whether the city is visited before. For example if Little Ho’s moving path is 1->2->3->2->3->1 his charisma will increase by 5.

Little Ho wants to maximize his charisma. However moving between cities costs action points. More precisely moving from city i to city j costs him Aij action points. Little Ho wants to know how many points of charisma he can get by using no more than M action points? He may start at any city.

输入

Line 1: N and M, the number of cities and the initial action points.

Line 2~N+1: An N x N matrix A. Aij is the action point cost as described above.

For 30% of the data: 2≤N≤5,1≤M≤50,0≤Aij≤10

For 60% of the data: 2≤N≤50,1≤M≤2000,0≤Aij≤10

For 100% of the data: 2≤N≤100,1≤M≤1,000,000,000,0≤Aij≤20

输出

The maximum points of charisma Little Ho can get.

样例提示

The optimal path is 1->2->3->1->2.

样例输入
3 10
0 2 3
4 0 2
3 4 0

样例输出

4


算法分析:

        显然,可以修改floyd算法,定义一个如下的状态方程

        dp(i,j,k)表示图中从i到j走k步的最小代价,则有如下的状态转移方程

        dp(i,j,k)=min{dp(i,l,k-1)+dp(l,j,k-1) for l = 0,1,2,...n-1}

        至于原问题的解,我们可以使用二分查找,即给定一个步数s,我们判断在s步内是否存在两个点i,j,使得从i走s步到j,并使用的代价不大于M


代码:

#include <iostream>
#include <string.h>
#include <vector>
#include <stdlib.h>
using namespace  std;

unsigned int NXUpperPow2(unsigned int v){
    --v;
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    return ++v;
}

unsigned int NXLowerPow2(unsigned int x){
    unsigned int v = NXUpperPow2(x);
    return v == x ? v : v >> 1;
}

unsigned int NXPow2(unsigned int x){
    int bc = 0;
    while(x){
        ++bc;
        x >>= 1;
    }
    return bc;
}

class Matrix{
public:
    friend inline Matrix operator * (const Matrix &lhs, const Matrix &rhs);
    friend inline Matrix QuickPow(const int n);
public:
    explicit Matrix(int iScale);
    Matrix();
public:
    vector<unsigned int>& operator[] (const int idx){
        return m_Elem[idx];
    }
    
    const vector<unsigned int> & operator[] (const int idx) const{
        return m_Elem[idx];
    }
    
    void SetScale(int iScale);
public:
    vector<vector<unsigned int > > m_Elem;
    int          m_iScale;
};

Matrix pm[32];

class Solution{
public:
    bool ReadData();
    int GetResult();
private:
    bool Check(const Matrix &m);
public:
    int N;
    int M;
    Matrix cost;
};

inline Matrix operator * (const Matrix &lhs, const Matrix &rhs){
    int iScale = lhs.m_iScale;
    int mv;
    Matrix result(iScale);
    for(int r = 0; r < iScale; ++r){
        for(int c = 0; c < iScale; ++c){
            result[r][c] = -1;
            for(int k = 0; k < iScale; ++k){
                if(lhs[r][k] == -1 || rhs[k][c] == -1){
                    continue;
                }
                mv = lhs[r][k] + rhs[k][c];
                if(mv < result[r][c])
                    result[r][c] = mv;
            }
        }
    }
    return result;
}

inline Matrix QuickPow(const int n){
    if(n == 1){
        return pm[0];
    }
    int p2 = NXLowerPow2(n);
    int l2 = NXPow2(n);
    return p2 == n ? pm[l2 - 1] : pm[l2 - 1] * QuickPow(n - p2);
}

Matrix::Matrix(int iScale){
    SetScale(iScale);
}

Matrix::Matrix(){
    
}

void Matrix::SetScale(int iScale){
    m_iScale = iScale;
    m_Elem.resize(iScale);
    for(int i = 0; i < iScale; ++i){
        m_Elem[i].resize(iScale);
    }
}

bool Solution::ReadData(){
    if(! (cin >> N)){
        return false;
    }
    
    cin  >> M;
    cost.SetScale(N);
    for(int r = 0; r < N; ++r){
        for(int c = 0; c < N; ++c){
            cin >> cost[r][c];
        }
        cost[r][r] = -1;
    }
    pm[0] = cost;
    int l = NXPow2(M);
    for(int i = 1; i < l; ++i){
        pm[i] = pm[i- 1] * pm[i - 1];
    }
    return true;
}

bool Solution::Check(const Matrix &m){
    for(int r = 0; r < N; ++r){
        for(int c = 0; c < N; ++c){
            if(m[r][c] <= M){
                return true;
            }
        }
    }
    
    return false;
}

int Solution::GetResult(){
    if(!Check(cost)){
        return 0;
    }
    
    int l = 1, r = M;
    int m;
    while(l < r){
        m = (l + r) >> 1;
        if(Check(QuickPow(m))){
            l = m + 1;
        }else{
            r = m - 1;
        }
    }
    while(!Check(QuickPow(l))){
        --l;
    }
    return l;
}

int main(){
    Solution so;
    while(so.ReadData()){
        cout << so.GetResult() << endl;
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值