loj 1316(spfa预处理+状压dp)
题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=27024
题意:求0-(n-1)的经过最多的标记的点的最短路。
思路:首先我们可以spfa预处理出起点到标记的最短距离,标记的点到终点的最短距离,然后就是状压dp了,dp[state][u]表示在该状态下到达点u的最短路径。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #include<vector> 7 using namespace std; 8 #define MAXN 555 9 #define FILL(a,b) memset(a,b,sizeof(a)) 10 #define inf 1<<30 11 12 struct Edge{ 13 int v,w; 14 Edge(int vv,int ww):v(vv),w(ww){} 15 }; 16 17 int n,m,s,bit[1<<17]; 18 int Initiate(int state) 19 { 20 int cnt=0; 21 while(state){ 22 cnt+=state&1; 23 state>>=1; 24 } 25 return cnt; 26 } 27 28 int dist[17][MAXN],pos[17]; 29 bool mark[MAXN]; 30 vector<Edge>g[MAXN]; 31 32 bool spfa(int vs,int dist[]) 33 { 34 fill(dist,dist+n,inf); 35 FILL(mark,false); 36 queue<int>que; 37 que.push(vs); 38 dist[vs]=0; 39 while(!que.empty()){ 40 int u=que.front(); 41 que.pop(); 42 mark[u]=false; 43 for(int i=0;i<g[u].size();i++){ 44 int v=g[u][i].v,w=g[u][i].w; 45 if(dist[u]+w<dist[v]){ 46 dist[v]=dist[u]+w; 47 if(!mark[v]){ 48 mark[v]=true; 49 que.push(v); 50 } 51 } 52 } 53 } 54 return dist[n-1]!=inf; 55 } 56 57 int dp[1<<17][17],ans1,ans2; 58 void Get_Dp() 59 { 60 for(int i=0;i<=(1<<s);i++) 61 for(int j=0;j<=s;j++)dp[i][j]=inf; 62 for(int i=0;i<s;i++){ 63 int p=pos[i]; 64 spfa(p,dist[i]); 65 dp[1<<i][i]=dist[s][p]; 66 } 67 ans1=0; 68 ans2=dist[s][n-1]; 69 for(int state=0;state<(1<<s);state++){ 70 int tmp=bit[state]; 71 for(int i=0;i<s;i++)if(state&(1<<i)){ 72 if(dist[i][n-1]!=inf&&dp[state][i]!=inf){ 73 if(tmp>ans1)ans1=tmp,ans2=dp[state][i]+dist[i][n-1]; 74 else if(tmp==ans1)ans2=min(ans2,dp[state][i]+dist[i][n-1]); 75 for(int j=0;j<s;j++)if(!(state&(1<<j))){ 76 dp[state|(1<<j)][j]=min(dp[state|(1<<j)][j],dp[state][i]+dist[i][pos[j]]); 77 } 78 } 79 } 80 } 81 printf("%d %d\n",ans1,ans2); 82 } 83 84 85 86 int main() 87 { 88 int _case,t=1; 89 scanf("%d",&_case); 90 for(int i=0;i<=(1<<15);i++)bit[i]=Initiate(i); 91 while(_case--){ 92 scanf("%d%d%d",&n,&m,&s); 93 for(int i=0;i<=n;i++)g[i].clear(); 94 for(int i=0;i<s;i++)scanf("%d",&pos[i]); 95 while(m--){ 96 int u,v,w; 97 scanf("%d%d%d",&u,&v,&w); 98 g[u].push_back(Edge(v,w)); 99 } 100 printf("Case %d: ",t++); 101 if(!spfa(0,dist[s])){ 102 puts("Impossible"); 103 continue; 104 } 105 Get_Dp(); 106 } 107 return 0; 108 }