HDU 5711 Ingress(状压dp 解决商旅推销员问题TSP)

Ingress

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


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
 

Source

【题意】

有n+1点(其中0为home)m条无向边,除0点外,每个点有一个权值a[i]。主人公从0出发,最后回到0,到达每个点,他可以取一次数,取完后,这个点的数值a[i]将减少b[i]。最多可以进行取数k次,回到0时,路程不能超过L。问可以取得的最大和。

【分析】

商旅推销员问题类似。

obvious,主人公走到某个点,一定会取数取的尽量多,并且不再回来(回来的话,还不如上次在这的时候取着。)。当然他也可以路过某个点而不取。

设状态为:

将每个点对应一个二进制位,为1的位代表走过的点,为0的位表示没走的点。(例如1001表示 点0和3走过了,1和2没走过)

用dp[i][j]表示状态i时,当前位于j点上,从0而来的最短距离。(i状态包含j)

dis[i][j]表示点i到j的最短路(floyd可求)

对于每一个状态,若dp[i][j] + dis[j][0] <= L 则满足路程限制。在此前提下,对状态i中的点,贪心法取k次最大值累加(每取一次a[i],要减掉b[i]),优先队列维护最为合适

【代码】

#include<bits/stdc++.h>
#define rep(i,s,t) for(int i=s;i<=t;i++)
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const int N=1e6+5;

int a[20],b[20];
int dis[20][20];
int dp[1<<17][20];
typedef pair<int,int> PII;
void floyd(int n)
{
    for(int k=0;k<=n;k++)
    {
        for(int i=0;i<=n;i++)
        {
            for(int j=0;j<=n;j++)
            {
                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
            }
        }
    }
}

int main()
{
    int cas=0,T,n,m,k,L;
    int u,v,w;
    cin>>T;
    while(T--)
    {
        cin>>n>>m>>k>>L;

        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)scanf("%d",&b[i]);
        memset(dis,0x3f,sizeof(dis));
        memset(dp,0x3f,sizeof(dp));
        while(m--)
        {
            scanf("%d%d%d",&u,&v,&w);
            dis[u][v]=dis[v][u]=min(dis[u][v],w);
        }
        floyd(n);

        dp[1][0]=0;
        for(int i=0;i<(1<<(n+1));i++) ///已经到过的点
        {
            for(int j=0;j<=n;j++)if(i&(1<<j)) ///当前所在的点
            {
                for(int t=0;t<=n;t++)if((i&(1<<t))==0) ///可以去的点
                {
                    dp[i|(1<<t)][t]=min(dp[i|(1<<t)][t],dp[i][j]+dis[j][t]); ///j->t
                }
            }
        }
        int ans=0;
        for(int i=0;i<(1<<(n+1));i++) ///状态
        {
            int cango=0;
            for(int j=0;j<=n;j++)
            {
                if((i&(1<<j))&&dp[i][j]+dis[j][0]<=L) ///i状态包含点j && 距离能回到0
                    cango=1;
            }
            if(!cango)continue; ///len too far
            int res=0;
            priority_queue<PII>q;
            for(int t=0;t<=n;t++)if(i&(1<<t))
            {
                q.push(PII(a[t],b[t]));
            }
            for(int t=0;t<k&&!q.empty();t++) ///最多选k次
            {
                PII u=q.top(); q.pop();
                res+=u.first;
                u.first-=u.second;
                q.push(u);
            }
            ans=max(ans,res);
        }
        printf("Case %d: %d\n",++cas,ans);
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/winter2121/article/details/80697373