题目链接:http://poj.org/problem?id=3311
//Floyd + 状态压缩DP
//题意是有N个城市(1~N)和一个PIZZA店(0),要求一条回路,从0出发,又回到0,而且距离最短
//也就是TSP(旅行商)问题,首先不难想到用FLOYD先求出任意2点的距离dis[i][j]
//接着枚举所有状态,用11位二进制表示10个城市和pizza店,1表示经过,0表示没有经过
//定义状态DP(S,i)表示在S状态下,到达城市I的最优值
//接着状态转移方程:DP(S,i) = min{DP(S^(1<<i-1),j) + dis[j][i],DP(S,i)},其中S^(1<<i-1)表示未到达城市i的所有状态,1<=j<=n
//对于全1的状态,即S = (1<<n)-1则表示经过所有城市的状态,最终还需要回到PIZZA店0
hdu 4284 Travel floyd + 状压DP
http://acm.hdu.edu.cn/showproblem.php?pid=4284
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<memory.h>
using namespace std;
const int inf=1<<29;
const int maxn=102;
int n,t,m,h,money,dp[1<<15][102],map[102][102];
struct node
{
int id,ci,di;
} p[maxn];
void floyd()
{
int i,j,k;
for(k=1; k<=n; k++)
{
for(i=1; i<=n; i++)
{
if(map[i][k]!=inf)
for(j=1; j<=n; j++)
{
if(map[k][j]!=inf&&map[i][j]>map[i][k]+map[k][j])
{
map[i][j]=map[i][k]+map[k][j];
}
}
}
}
}
void DP()
{
int i,j,k;
floyd();
memset(dp,-1,sizeof(dp));
for (i = 0; i < h; ++i)
{
int v = p[i].id;
if (money - map[1][v] - p[i].di >= 0)
{
dp[1<<i][i] = money - map[1][v] - p[i].di + p[i].ci;
}
}
for (i = 1; i <(1<<h); ++i)
{
for (j = 0; j < h; ++j)
{
if (dp[i][j] == -1) continue;//对于以j结尾的i路线存在
int u = p[j].id;
for (k = 0; k < h; ++k) //查看j是否可到k
{
if ((i&(1<<k)) == 0)
{
int v = p[k].id;
if (dp[i][j] - map[u][v] - p[k].di >= 0) //可到
{
int now = (i^(1<<k));
if (dp[now][k] == -1 || dp[now][k] < dp[i][j] - map[u][v] - p[k].di + p[k].ci)
dp[now][k] = dp[i][j] - map[u][v] - p[k].di + p[k].ci;
}
}
}
}
}
}
int main()
{
cin>>t;
while(t--)
{
int i,j,k,a,b,c;
cin>>n>>m>>money;
for(i=0; i<=n; i++)
{
for(j=0; j<=n; j++)
{
if(i!=j) map[i][j]=inf;
else map[i][j]=0;
}
}
for(i=1; i<=m; i++)
{
cin>>a>>b>>c;
if(map[a][b]>c)
{
map[a][b]=map[b][a]=c;
}
}
cin>>h;
for(i=0; i<h; i++)
{
cin>>p[i].id>>p[i].ci>>p[i].di;
}
DP();
bool flag = false ;
for (i =0; i <h; ++i)
{
if (dp[((1<<h) - 1)][i] - map[p[i].id][1]>=0)
{
flag = true;
break;
}
}
if (flag) printf("YES\n");
else printf("NO\n");
}
return 0;
}