Hdu 5711 Ingress【TSP+贪心】

186 篇文章 0 订阅
166 篇文章 1 订阅

Ingress

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 102400/65535 K (Java/Others)
Total Submission(s): 326    Accepted Submission(s): 144


Problem Description
Brickgao, who profited from your accurate calculating last year, made a great deal of money by moving bricks. Now he became ``gay shy fool'' again and recently he bought an iphone and was deeply addicted into a cellphone game called Ingress. Now he is faced with a problem so he turns to you for help again. We make some slight modifications based on the original rules, so please draw attention to the details below.

There are  N  portals (indexed from 1 to  N ) around Brickgao's home, and he can get some substances called XM by hacking the portals. It's known that for each portal  i , he can get  Ai  XM during the first hack, and after each hack, the amount of XM he will get during the next hack will decrease by  Bi . If the amount of XM he can get is less than or equal to zero, Brickgao can't get XM from that portal anymore. For the  i -th portal, if  Ai=10,Bi=2  and he hacks 3 times, he will get 10, 8, 6 XM during each hack.

There are  M  bidirectional roads between some pairs of portals and between Brickgao's home and some portals. Now he is eager to start his Ingress journey from home and finally return home, but due to the extremely hot weather, Brickgao will feel sick when you hack more than  K  times or the distance he covers is more than  L . So how much XM he can get at most during this journey?

 

Input
The first line contains a single integer  T(T20) , indicating the number of test cases.

The first line of each case are four integers  N(1N16),M(0MN(N+1)2),K(1K50)  and  L(2L2000) .
The second line of each case contains  N  non-negative integers where the  i -th denotes  Ai(Ai500) .
The third line of each case contains  N  non-negative integers where the  i -th denotes  Bi(Bi50) .
Each of next  M  line contains 3 non-negative integers  u,v(0u,vn)  and  c(0c1000)  , denotes that there is a road with the length of  c  between the  u -th and the  v -th portal. If  u  or  v  equals to 0, it means Brickgao's home.
 

Output
For each test case, output the case number first, then the amount of maximum XM Brickgao can get.
 

Sample Input
  
  
2 1 1 3 2 5 3 0 1 1 3 6 3 5 10 7 5 2 3 1 0 1 3 0 2 1 0 3 1 1 2 2 2 3 3 1 3 4
 

Sample Output
  
  
Case 1: 7 Case 2: 16

题目大意:


给你N个可以攻击的点,M条无向边,我们可以攻击点多次,但是最多可以攻击K次。

这个人从0点作为起点出发,最终要回到0点,全程最长可以走过的路径总长度为L.

现在已知攻击每个点的收益,和攻击一次点之后收益减少的量。

问最多可以获得多少收益。


思路:

①首先我们跑一遍Floyd,求出两点间最短路。


②然后我们O(2^n*n*n)的状压dp求出dp【i】【j】,表示走过的点状态为i,最终到达的点是j的最小路径花费。

那么如果有:dp【i】【j】+mp【j】【0】<=L,那么这条路径上走过的所有点都可以进行攻击。


③那么对于所有:dp【i】【j】+mp【j】【0】<=L的状态i,我们维护一个优先队列,将状态i走过的点都放进去,然后每次取最高价值的点进行攻击即可。

那么就能知道每个走过的点都需要攻击多少次能够达到最优了。

维护所有情况的最小值即可。


Ac代码:


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
struct node
{
    int u,val;
    bool friend operator <(node a,node b)
    {
        return a.val<b.val;
    }
};
int n,m,p,c;
int mp[25][25];
int val[25];
int del[25];
int dp[(1<<17)+50][18];
void init()
{
    for(int i=0;i<=(1<<(n+1));i++)
    {
        for(int j=0;j<=n;j++)
        {
            dp[i][j]=0x3f3f3f3f;
        }
    }
    for(int i=0;i<=n;i++)
    {
        for(int j=0;j<=n;j++)
        {
            mp[i][j]=0x3f3f3f3f;
        }
        mp[i][i]=0;
    }
}
void Floyd()
{
    for(int i=0;i<=n;i++)
    {
        for(int j=0;j<=n;j++)
        {
            for(int k=0;k<=n;k++)
            {
                mp[j][k]=min(mp[j][k],mp[j][i]+mp[i][k]);
            }
        }
    }
}
void Tsp()
{
    dp[1][0]=0;
    int end=(1<<(n+1));
    for(int i=1;i<end;i++)
    {
        for(int j=0;j<=n;j++)
        {
            if((i&(1<<j))==0)continue;
            for(int k=1;k<=n;k++)
            {
                int q=(i|(1<<k));
                dp[q][k]=min(dp[q][k],dp[i][j]+mp[j][k]);
            }
        }
    }
}
void Slove()
{
    int output=0;
    int end=(1<<(n+1));
    for(int i=1;i<end;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(dp[i][j]+mp[j][0]<=c)
            {
                priority_queue<node>s;
                for(int k=1;k<=n;k++)
                {
                    if((i&(1<<k))>0)
                    {
                        node now;
                        now.u=k;
                        now.val=val[k];
                        s.push(now);
                    }
                }
                int tmp=p;
                int sum=0;
                while(!s.empty())
                {
                    if(tmp>0)
                    {
                        node now=s.top();
                        s.pop();
                        if(now.val<0)break;
                        sum+=now.val;
                        now.val-=del[now.u];
                        s.push(now);
                    }
                    else break;
                    tmp--;
                }
                while(!s.empty())s.pop();
                output=max(output,sum);
            }
        }
    }
    printf("%d\n",output);
}
int main()
{
    int t;
    int kase=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d%d",&n,&m,&p,&c);
        init();
        for(int i=1;i<=n;i++)scanf("%d",&val[i]);
        for(int i=1;i<=n;i++)scanf("%d",&del[i]);
        for(int i=0;i<m;i++)
        {
            int x,y,w;
            scanf("%d%d%d",&x,&y,&w);
            mp[x][y]=min(mp[x][y],w);
            mp[y][x]=min(mp[y][x],w);
        }
        printf("Case %d: ",++kase);
        Floyd();
        Tsp();
        Slove();
    }
}









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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值