BZOJ 1097 [POI2007]旅游景点atr

来源:互联网 发布:一起走软件登录 编辑:程序博客网 时间:2024/04/26 02:50

题意:FGD想从成都去上海旅游。在旅途中他希望经过一些城市并在那里欣赏风景,品尝风味小吃或者做其他的有趣的事情。经过这些城市的顺序不是完全随意的,比如说FGD不希望在刚吃过一顿大餐之后立刻去下一个城市登山,而是希望去另外什么地方喝下午茶。幸运的是,FGD的旅程不是既定的,他可以在某些旅行方案之间进行选择。由于FGD非常讨厌乘车的颠簸,他希望在满足他的要求的情况下,旅行的距离尽量短,这样他就有足够的精力来欣赏风景或者是泡MM了^_^. 整个城市交通网络包含N个城市以及城市与城市之间的双向道路M条。城市自1至N依次编号,道路亦然。没有从某个城市直接到它自己的道路,两个城市之间最多只有一条道路直接相连,但可以有多条连接两个城市的路径。任意两条道路如果相遇,则相遇点也必然是这N个城市之一,在中途,由于修建了立交桥和下穿隧道,道路是不会相交的。每条道路都有一个固定长度。在中途,FGD想要经过K(K<=N-2)个城市。成都编号为1,上海编号为N,而FGD想要经过的N个城市编号依次为2,3,…,K+1. 举例来说,假设交通网络如下图。FGD想要经过城市2,3,4,5,并且在2停留的时候在3之前,而在4,5停留的时候在3之后。那么最短的旅行方案是1-2-4-3-4-5-8,总长度为19。注意FGD为了从城市2到城市4可以路过城市3,但不在城市3停留。这样就不违反FGD的要求了。并且由于FGD想要走最短的路径,因此这个方案正是FGD需要的。

我们注意到K非常小,所以需要经过的城市可以状压起来,预处理出每对必须经过的城市之间的最短路,之后由小的状态向大的状态转移就好了,这题常数卡得比较紧,最短路尽量写heap+dijkstra,并且DP时判掉冗余状态,就能过了

#include<iostream>#include<algorithm>#include<cstring>#include<cstdio>#include<vector>#include<queue>using namespace std;const int maxn=20000+10;const int maxm=1<<21;int d[maxn],dis[23][maxm],n,m,k,f[23][23],pre[maxn],id[maxn],vis[maxn];bool inq[23][maxm];struct node{  int to,cost;};struct arr{  int p,s;};struct vv{  int p,v;  bool operator <(const vv g)const  {    return v>g.v;  }};priority_queue<vv> Q;vector<node> g[maxn];void dijkstra(int p){  memset(vis,0,sizeof(vis));  memset(d,127/2,sizeof(d));  d[id[p]]=0;Q.push((vv){id[p],d[id[p]]});  while(!Q.empty())  {    vv x=Q.top();Q.pop();if(vis[x.p]) continue;    vis[x.p]=1;    for(int i=0;i<g[x.p].size();i++)    {      node e=g[x.p][i];int v=e.to;      if(d[v]>d[x.p]+e.cost)      {        d[v]=d[x.p]+e.cost;        Q.push((vv){v,d[v]});      }    }  }  for(int i=1;i<=k+1;i++)    f[p][i]=d[i];  f[p][k+2]=d[n];}void spfa(int p){  memset(d,127/2,sizeof(d));  d[id[p]]=0;queue<int> Q;Q.push(id[p]);inq[p][id[p]]=1;  while(!Q.empty())  {    int x=Q.front();Q.pop();inq[p][x]=0;    for(int i=0;i<g[x].size();i++)    {      node e=g[x][i];int v=e.to;      if(d[v]>d[x]+e.cost)      {        d[v]=d[x]+e.cost;        if(!inq[p][v])        {          inq[p][v]=1;          Q.push(v);        }      }    }  }  for(int i=1;i<=k+1;i++)    f[p][i]=d[i];  f[p][k+2]=d[n];}void dp(){  memset(inq,0,sizeof(inq));queue<arr> Q;  memset(dis,127/2,sizeof(dis));dis[1][0]=0;  for(int s=0;s<(1<<k);s++)    for(int x=1;x<=k+2;x++)      for(int i=1;i<=k+2;i++)        if((pre[id[i]]&s)==pre[id[i]]&&i!=x)        {             int ns=s;          if(i>1&&i<=k+1) ns=s|(1<<(i-2));          if(dis[i][ns]>dis[x][s]+f[x][i])            dis[i][ns]=dis[x][s]+f[x][i];        }}  int main(){  //freopen("1097.in","r",stdin);  //freopen("1097.out","w",stdout);  scanf("%d%d%d",&n,&m,&k);  for(int i=1;i<=m;i++)  {    int u,v,c;scanf("%d%d%d",&u,&v,&c);    g[u].push_back((node){v,c});    g[v].push_back((node){u,c});  }  for(int i=1;i<=k+1;i++) id[i]=i;  id[k+2]=n;  for(int i=1;i<=k+2;i++)    dijkstra(i);  int l;scanf("%d",&l);  for(int i=1;i<=l;i++)  {    int x,y;scanf("%d%d",&x,&y);    if(x<n) pre[y]+=1<<(x-2);    else pre[y]+=1<<(k+1);  }  dp();  printf("%d\n",dis[k+2][(1<<k)-1]);  return 0;}  
0 0