hdu 4284 Travel

题意:不想说了。。。

 

我们只需要关心被选择的点,先预处理出来每两点间的最短路,然后问题就变成找到一条从1出发最后回到1且经过所有被选择点的最长路径,赤裸裸的TSP问题,状态压缩可破之。

最初写了个spfa,但是效率无比低,其实对于这种特殊的状态转移(只能小的向大的转移),可以直接递推。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 #include<iostream>
 7 #include<string>
 8 #include<vector>
 9 #include<queue>
10 #include<stack>
11 #include<set>
12 #include<map>
13 #include<bitset>
14 using namespace std;
15 typedef long long ll;
16 typedef pair<int,int> pii;
17 const int N=110;
18 const int M=20;
19 const int inf=~0u>>2;
20 int dp[M][1<<16];
21 bool vis[M][1<<16];
22 int d[N][N],dis[M][M];
23 int hash[M],C[M],D[M],h;
24 struct node{
25     int cur,mask,val;
26     node(){}
27     node(int _cur,int _mask,int _val):
28         cur(_cur),mask(_mask),val(_val){}
29 };
30 bool solve(int Money){
31     for(int i=0;i<h;i++)
32         for(int j=0;j<1<<h;j++)
33             dp[i][j]=-inf;
34     for(int i=0;i<h;i++)
35         if(Money-d[1][hash[i]]-D[i]>=0)
36             dp[i][1<<i]=max(dp[i][1<<i],Money-d[1][hash[i]]-D[i]+C[i]);
37     for(int mask=0;mask<1<<h;mask++){
38         for(int i=0;i<h;i++){
39             if(dp[i][mask]==-inf)continue;
40             for(int j=0;j<h;j++){
41                 if(j==i)continue;
42                 if(dp[i][mask]<dis[i][j])continue;
43                 if(!mask&(1<<j))continue;
44                 if(dp[i][mask]-dis[i][j]-D[j]<0)continue;
45                 dp[j][mask|(1<<j)]=max(dp[j][mask|(1<<j)],dp[i][mask]-dis[i][j]-D[j]+C[j]);
46             }
47         }
48     }
49     int ans=-inf;
50     for(int i=0;i<h;i++)
51         ans=max(ans,dp[i][(1<<h)-1]-dis[1][hash[i]]);
52     return ans>=0;
53 }
54 int main(){
55     int T,n,m,Money;scanf("%d",&T);
56     while(T--){
57         scanf("%d%d%d",&n,&m,&Money);
58         for(int i=1;i<=n;i++)
59             for(int j=1;j<=n;j++)
60                 d[i][j]=i==j?0:inf;
61         for(int i=1;i<=m;i++){
62             int u,v,len;scanf("%d%d%d",&u,&v,&len);
63             d[u][v]=d[v][u]=min(d[u][v],len);
64         }
65         for(int k=1;k<=n;k++)
66             for(int i=1;i<=n;i++)
67                 for(int j=1;j<=n;j++)
68                     if(d[i][k]!=inf&&d[k][j]!=inf)
69                         d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
70         scanf("%d",&h);
71         int start=-1;
72         for(int i=0;i<h;i++){
73             scanf("%d%d%d",&hash[i],&C[i],&D[i]);
74             if(hash[i]==1)start=i;
75         }
76         bool flag=0;
77         for(int i=0;i<h;i++)
78             for(int j=0;j<h;j++){
79                 dis[i][j]=d[hash[i]][hash[j]];
80                 if(dis[i][j]==inf)flag=1;
81             }
82         puts(flag||!solve(Money)?"NO":"YES");
83     }
84     return 0;
85 }

 

 

转载于:https://www.cnblogs.com/silver-bullet/p/3287849.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值