给出N个城市,城市之间的路径需要一定的花费。其中一些城市(H<=15)是必达的,在这些城市可以打工赚钱,但前提是有足够的钱购买这些城市的工作许可。问是否能获得所有的许可并且最终回到起点。
这题和我之前出过的一个题很像。。http://acm.csu.edu.cn/onlinejudge/problem.php?id=1175
先对这H个点做一遍最短路,这题的点比较少,直接用FLOYD,然后对这H个点用哈密顿回路DP就可以了。
需要注意的是一个城市允许经过多次,如果第一次来这个城市时不够钱购买工作许可可以在其他城市工作赚了钱之后再回来拿。。。
1 #include <string.h> 2 #include <stdio.h> 3 #include <algorithm> 4 #include <queue> 5 #define MAXE 10005 6 #define MAXN 205 7 #define INF 0x3f3f3f3f 8 #define rep(i,a,n) for(int i=a;i<=n;i++) 9 using namespace std; 10 int cas,n,m,money,cts; 11 int tu,tv,tw; 12 int map[20][20],mapb[105][105]; 13 int ci[20],di[20],id[20],cits,full; 14 int dp[70000][17]; 15 int main(){ 16 //freopen("test.in","r",stdin); 17 scanf("%d",&cas); 18 while(cas--){ 19 scanf("%d%d%d",&n,&m,&money); 20 rep(i,1,n)rep(j,1,n)mapb[i][j]=(i==j?0:INF); 21 rep(i,1,m){ 22 scanf("%d%d%d",&tu,&tv,&tw); 23 mapb[tu][tv]=mapb[tv][tu]=std::min(mapb[tu][tv],tw); 24 } 25 //FLOYD 26 rep(k,1,n)rep(i,1,n)rep(j,1,n) 27 mapb[i][j]=std::min(mapb[i][j],mapb[i][k]+mapb[k][j]); 28 scanf("%d",&cts);cts--; 29 //put the city 1 to the last position 30 rep(i,0,cts)scanf("%d%d%d",&id[i],&ci[i],&di[i]); 31 id[++cts]=1,ci[cts]=di[cts]=0; 32 //init the chosen city map 33 rep(i,0,cts)rep(j,0,cts)map[i][j]=mapb[id[i]][id[j]]; 34 full=(1<<(cts+1))-1; 35 //Hamilton 36 rep(s,0,full)rep(i,0,cts)dp[s][i]=-INF; 37 dp[0][cts]=money; 38 rep(s,0,full)rep(i,0,cts)if(dp[s][i]!=-INF){ 39 rep(j,0,cts)if((s>>j&1)==0&&dp[s][i]>=map[i][j]){ 40 int nmax=dp[s][i]-map[i][j]-di[j]; 41 if(nmax<0)continue; 42 if(nmax+ci[j]>dp[s|1<<j][j])dp[s|1<<j][j]=nmax+ci[j]; 43 } 44 } 45 int ans=-1; 46 rep(i,0,cts)ans=std::max(ans,dp[full][i]); 47 printf(dp[full][cts]>=0?"YES\n":"NO\n"); 48 } 49 }