http://acm.hdu.edu.cn/showproblem.php?pid=4284
给n个点(100),m条带权无向边,要求必须经过h个点,初始有money块钱,问能否把所有h个点都访问,并最后回到1.
访问这h个点有个前提条件,就是到该点时,钱要大于d[i],则访问后会扣点d【i】块,但是会返回c[i]块,当然 走边权也要花钱。
flody 预处理出最短路
把h个状态压位,dp[state][i]表示已经访问了state里,位为1的所有点,并且最后停留在点i时的最大金钱,则转移就是,判断当前金钱是否大于等于 【当前点到下一点的边权花费】+d【i】,
若大于则可以进去,并扣掉该部分钱,并得到c[i],更新状态,并push入队列
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
const double pi=acos(-1.0);
double eps=0.000001;
const long long mod= 1000000000+7;
const int maxn=110;
int e[maxn][maxn];
int c[maxn],d[maxn],idx[maxn];
int dp[1<<16][20];
int inf=1e8;
struct node
{
int state;
int id;
node() {}
node(int a,int b)
{
state=a;
id=b;
}
};
queue<node > q;
int main()
{
int t;
cin>>t;
while(t--)
{
memset(dp,-1,sizeof dp);
while(!q.empty())q.pop();
int n,m,money;
scanf("%d%d%d",&n,&m,&money);
int x,y,w;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(i==j) e[i][j]=0;
else e[i][j]=inf;
for (int i=1; i<=m; i++)
{
scanf("%d%d%d",&x,&y,&w);
//if (w<e[x][y])
e[x][y]=min(e[x][y],w);
e[y][x]=e[x][y];
}
for(int k=1; k<=n; k++)
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(e[i][j]>e[i][k]+e[k][j] )
e[i][j]=e[i][k]+e[k][j];
int h;
cin>>h;
for (int i=1; i<=h; i++)
{
scanf("%d%d%d",&x,&y,&w);
c[x]=y;
d[x]=w;
idx[i]=x;
}
if (!h)
{
printf("YES\n");
continue;
}
for (int i=1; i<=h; i++)
{
int id=idx[i];
if (money>=e[1][id]+d[id])
{
dp[1<<(i-1)][i]=money-( e[1][id]+d[id] )+c[id];
q.push(node(1<<(i-1),i));
}
}
while(!q.empty())
{
node t=q.front();
q.pop();
int state=t.state;
for (int i=1; i<=h; i++)
{
int id=idx[i];
if (( (1<<(i-1))&state)==0)
{
int state2=state|(1<<(i-1));
if (dp[state][t.id]>=d[id]+e[idx[t.id]][id])
{
if (dp[state2][i]==-1)
{
dp[state2][i]=dp[state][t.id]-d[id]+c[id]-e[idx[t.id]][id];
q.push(node(state2,i));
}
else
dp[state2][i]=max(dp[state2][i],dp[state][t.id]-d[id]+c[id]-e[idx[t.id]][id]);
}
}
}
}
int ans=(1<<h)-1;
int flag=0;
for (int i=1; i<=h; i++)
{
//printf("%d\n",dp[ans][i]);
int id=idx[i];
if (dp[ans][i]!=-1&&dp[ans][i]>=e[id][1]) flag=1;
}
if (flag) printf("YES\n");
else printf("NO\n");
}
return 0;
}