题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4284
题目大意:给你N个城市(1-N),M条路,初始身上有V元钱,接下来M行,每行三个数u,e,d,为u到e的路花费为d。
接下来有K个城市必须要去游历,在每个城市可以赚得c元钱,但是要先花费d元钱学习技能,问你能否遍历完这k个城市最后回到1号城市。
解题思路:首先用floyd跑出来所有城市的距离,然后判断第一个城市是否在所要游历的城市里,如果在,就记录下位置(初始化用),如果不在,就最后虚拟一个点,花费和收入都为0,即为城市1,然后就是给定K个点,求最佳顺序问题了,最后判断剩余的钱是否能回到初始点。
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f3f
struct node
{
int id,c,d;
}s[20];
int dp[1<<16][17],dis[103][103];
int n,m,v,k,pos;
void init()
{
memset(dp,-1,sizeof(dp));
memset(dis,inf,sizeof(dis));
for(int i=0;i<=n;i++)
dis[i][i]=0;
}
void floyd()
{
for(int k = 0; k < n; ++k)
for(int i = 0; i < n; ++i)
for(int j = 0; j < n; ++j)
if(dis[i][k] + dis[k][j] < dis[i][j])
dis[i][j] = dis[i][k] + dis[k][j];
}
void solve()
{
int num=(1<<k);
if(v-s[pos].d>=0) //初始化
dp[1<<pos][pos]=v-s[pos].d+s[pos].c;
dp[0][pos]=v;
for(int i=0; i<num; i++)
for(int j=0; j<k; j++)
{
if(dp[i][j]==-1) continue;
for(int k1=0;k1<k;k1++)
if( !(i&(1<<k1)) )
{
if(dp[i][j]-s[k1].d-dis[ s[k1].id ][ s[j].id ]>=0)
dp[ i|(1<<k1) ][k1]=max(dp[ i|(1<<k1) ][k1],dp[i][j]-s[k1].d+s[k1].c-dis[ s[k1].id ][ s[j].id ]);
}
}
bool flog=false;
for(int i=0;i<k;i++)
{
if(dp[num-1][i]>=dis[0][s[i].id])
{flog=true;break;}
}
printf(flog?"YES\n":"NO\n");
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int u,e,d;
init();
scanf("%d%d%d",&n,&m,&v);
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&u,&e,&d);
u--;e--;
if(dis[u][e]>d)
dis[u][e]=d,dis[e][u]=d;
}
floyd();
scanf("%d",&k);
pos=-1; //记录1点的位置
for(int i=0;i<k;i++)
{
scanf("%d%d%d",&s[i].id,&s[i].c,&s[i].d);
s[i].id--;
if(s[i].id==0) pos=i;
}
if(pos==-1)
{
s[k].id=0;s[k].c=0;s[k].d=0;
pos=k++;
}
solve();
}
return 0;
}
/*
2
4 5 10
1 2 1
2 3 2
1 3 2
1 4 1
3 4 2
3
1 8 5
2 5 2
3 10 1
YES
2 1 100
1 2 10000
1
2 100000 1
NO
*/