HDU 4284 Travel
/*摘自网络
因为必须经过H个点,H<=15,安排一个顺序使得能遍历完H个城市,可以用状态DP做。
用Floyd求任意两点之间的最短距离,也就是最小路费。
状态DP求经过某些城市集合s,最后到达某个城市i获得的最大收益,用f[s][i]表示。
最后要回到起始点1,这样判断是否能从f[all][i]状态是否能回到1点即可,all是所有的必经点。
PS:比赛的时候不是这么想,比赛时是把回到起始点1虚拟成n+1点了,这样就变成了H+1个必经点,还超时过,囧~。当时思路就堵住了呢。
有暴搜代替这个状态DP,也能过,暴搜应该是更快吧,因为没有最优解的要求,只要能回到起始点就行。
/*
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int N=101;
const int NN=16;
const int inf=0x80808080;
int g[N][N],w[NN][NN];
int label[NN],c[NN],d[NN];
int T,n,m,num,sta;
bool dfs(int x,int money,int stat) {
if(stat==(1<<num)-1 && money>=w[x][0]){
return true;
}
for(int i=0;i<num;i++) if((stat&(1<<i))==0){
if(money-d[i]-w[x][i]>=0) {
if(dfs(i,money-d[i]-w[x][i]+c[i],stat^(1<<i))) return true;
}
}
return false;
}
int main() {
scanf("%d",&T);
while(T--) {
scanf("%d%d%d",&n,&m,&sta);
memset(g,0x3f,sizeof(g));
for(int i=0;i<n;i++) g[i][i]=0;
for(int i=0;i<m;i++) {
int s,t,w;
scanf("%d%d%d",&s,&t,&w);
s--;t--;
g[s][t]=min(g[s][t],w);
g[t][s]=min(g[t][s],w);
}
scanf("%d",&num);
int havezero=false;
for(int i=0;i<num;i++) {
scanf("%d%d%d",&label[i],&c[i],&d[i]);
label[i]--;
if(label[i]==0) {
havezero=true;
swap(label[i],label[0]);
swap(c[i],c[0]);
swap(d[i],d[0]);
}
}
if(!havezero) {
label[num]=c[num]=d[num]=0;
swap(label[num],label[0]);
swap(c[num],c[0]);
swap(d[num],d[0]);
num++;
}
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++) g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
for(int i=0;i<num;i++)
for(int j=0;j<num;j++) w[i][j]=g[label[i]][label[j]];
bool yes=dfs(0,sta,0);
if(yes) puts("YES");
else puts("NO");
}
return 0;
}