您的位置:首页 > 其它

hdu4284Travel 状态dp

2015-10-09 19:19 211 查看
//n个城市,m条路,过每条路需要花费钱
//在每个城市花费d[i]得到工作资格可以赚c[i]的钱
//现在手上有num钱,问能否从1点开始,在给定的h(h<=15)个城市找到
//工作在回到1点
//除了这h点的其他点不能工作,可以经过这h个点不工作
//可以先用一个floyd将任意两点的最短距离求出
//由于h很小,可以用状态压缩来做,1表示已经在这个城市工作过,0表示没有
//dp[i][j]表示状态为i,当前位置为j的最多的钱数
//然后用一个队列维护一下
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
using namespace std ;
const int maxn = 110 ;
const int inf = 0x3f3f3f3f ;
int map[maxn][maxn] ;
int n , m , num ;
int p[maxn] , c[maxn] , d[maxn] ;
int vis[1<<15][maxn] ;
int dp[1<<15][15] ;
void floyd()
{
for(int k = 1;k <= n;k++)
for(int i = 1;i <= n;i++)
for(int j = 1;j <= n;j++)
map[i][j] = min(map[i][j] , map[i][k] + map[k][j]) ;
}
int main()
{
//freopen("in.txt" , "r" , stdin) ;
int t ;
scanf("%d" , &t) ;
while(t--)
{
scanf("%d%d%d" , &n , &m , &num) ;
for(int i = 1;i <= n;i++)
for(int j = 1;j <= n;j++)
map[i][j] = j == i ? 0 : inf ;
for(int i = 1;i <= m;i++)
{
int u , v , w ;
scanf("%d%d%d"  , &u , &v , &w) ;
if(map[u][v] > w)
map[u][v] = map[v][u] = w ;
}
floyd() ;
int h  ;
scanf("%d" , &h) ;
for(int i = 0;i < h;i++)
scanf("%d%d%d" , &p[i] , &c[i] , &d[i]) ;
memset(dp , -1 , sizeof(dp)) ;
queue<int>que ;
memset(vis , 0 , sizeof(vis)) ;
for(int i = 0;i < h;i++)
if(num - map[1][p[i]] - d[i] > 0)
{
dp[1<<i][i] = num - map[1][p[i]] - d[i] + c[i] ;
que.push(1<<i) ;
que.push(i) ;
vis[1<<i][i] = 1 ;
}
while(que.size())
{
int s = que.front() ; que.pop() ;
int pos = que.front();que.pop() ;
vis[s][pos] = 0 ;
for(int i = 0;i < h;i++)
{
if(((1<<i)&s) == 0 && dp[s][pos] - map[p[pos]][p[i]] - d[i] > 0)
if(dp[s][pos] - map[p[pos]][p[i]] - d[i] + c[i] > dp[s^(1<<i)][i])
{
dp[s^(1<<i)][i] = dp[s][pos] - map[p[pos]][p[i]] - d[i] + c[i] ;
if(!vis[s^(1<<i)][i])
{
que.push(s^(1<<i)) ;
que.push(i) ;
}
}
}
}
bool flag = false ;
for(int i = 0;i < h;i++)
if(dp[(1<<h)-1][i] - map[p[i]][1] > 0)
{
flag = true ;
break ;
}
if(flag)puts("YES") ;
else puts("NO") ;
}
return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: