ZOJ2845-The Best Travel Design

来源:互联网 发布:科比06赛季所有数据 编辑:程序博客网 时间:2024/05/20 02:30

题目大意:给你一个无向图,一共有N个节点,你必须要经过给定的M个节点,输出最多游览的节点数;

题目解析:如果考虑游览的过程,那么顺序显得十分复杂,不仅不容易记录而且十分耗时间,所以我们需要采用状态压缩法:int p[20];p[i]=2*(i-1),dp[s][j],s表示当前已经游览的节点数的集合(不需要考虑顺序),j表示当前在第j个节点上,很容易发现在dp转移的时候,我们必须要知道最短路径,所以一开始就要处理好图的最短路径,dp转移的时候只需要枚举各个节点即可;

注意:判断j在不在s这个集合中,不在的话p[j]&s=0;

AC代码:

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<string>using namespace std;const double inf =1e9;int main(){int n,m,k,ans,i,j,K,arrive,cnt,number,to,x,y,len,kind,s,p[20];double dis,dp[1<<15][20],cost[20][20],stay[20];for(i=1;i<=20;i++)p[i]=1<<(i-1);while(scanf("%d%d%d",&n,&m,&K)!=EOF){arrive=0;for(i=1;i<20;i++){for(j=1;j<20;j++)cost[i][j]=inf;}for(i=0;i<m;i++){scanf("%d",&number);arrive+=p[number];}for(i=1;i<=n;i++)scanf("%lf",stay+i);while(scanf("%d%d%d%d",&x,&y,&len,&kind)){if(x+y+len+kind==0)break;if(kind==0)dis=len/80.0;else dis=len/120.0;cost[x][y]=min(cost[x][y],dis);cost[y][x]=cost[x][y];}for(k=1;k<=n;k++)for(i=1;i<=n;i++)for(j=1;j<=n;j++)cost[i][j]=min(cost[i][j],cost[i][k]+cost[k][j]);for(i=1;i<=n;i++)cost[i][i]=0;int max_s=1<<n;for(s=0;s<max_s;s++)for(j=1;j<=n;j++)dp[s][j]=inf;dp[0][1]=0;for(s=0;s<max_s;s++)for(j=1;j<=n;j++)if(dp[s][j]!=inf)for(k=1;k<=n;k++)if(!(p[k]&s)){to=s+p[k];if(dp[to][k]>dp[s][j]+cost[j][k]+stay[k]&&to<max_s)dp[to][k]=dp[s][j]+cost[j][k]+stay[k];}ans=0;for(s=0;s<max_s;s++){if((s&arrive)==arrive){for(j=1;j<=n;j++){if(dp[s][j]!=inf&&dp[s][j]+cost[j][1]<12*K){cnt=0;for(k=1;k<=n;k++)if(s&p[k])cnt++;if(cnt>ans)ans=cnt;}}}}if(ans==0)cout<<"No Solution"<<endl;else cout<<ans<<endl;}return 0;}


0 0
原创粉丝点击